Compare commits

...

157 Commits

Author SHA1 Message Date
ibuler
6def93b833 perf: add aggreement 2026-02-02 18:47:25 +08:00
zhaojisen
05c78d7d90 perf: Control the button through configuration 2026-01-27 13:55:55 +08:00
fit2bot
c638e39dd4 perf: Optimize the logic of style variables (#5301)
* change theme

* perf: Update Dockerfile with new base image tag

* optimism some icon

* perf: Update Dockerfile with new base image tag

* Modify the styles of some prompt-related components

* Make some adjustments to the styles of the table and menu

* perf: Optimize the logic of style variables

* restore radius style

* reset some styles

* border and main style

* Optimize the style of the shuttle box

* change some styles

* adapt backend color

* Optimize the background color when the menu is expanded

* Modify the display format of the logo

* perf: navleft remove login_title

---------

Co-authored-by: zhaojisen <1301338853@qq.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: feng <1304903146@qq.com>
2026-01-26 10:32:21 +08:00
w940853815
1c527e9d77 perf: Translate ticket status 2026-01-22 14:31:25 +08:00
w940853815
eb9c9344eb perf: Translate quick filter 2026-01-22 11:22:15 +08:00
feng
6d8a931132 perf: Ticket action 2026-01-21 16:10:14 +08:00
w940853815
8cd3c5fa47 fix: Don't repeat the error message. 2026-01-21 15:51:17 +08:00
zhaojisen
ed770bd629 fix: Fix the icon display issue of the cloud synchronization card 2026-01-21 11:28:47 +08:00
feng
bdeded024d perf: Change secret execution detail remove recipients 2026-01-21 11:28:28 +08:00
w940853815
771ee96a1a fix: MFA display problem on user detail page 2026-01-20 16:48:59 +08:00
w940853815
dd9b40de20 fix: Ensure password is converted to string before encryption 2026-01-20 16:48:23 +08:00
zhaojisen
d360cadadb fix: Fix the issue where the current node asset cannot be displayed independently 2026-01-20 16:19:57 +08:00
fit2bot
86814693af fix: Fix the issue of detail navigation for account template settings (#5302) 2026-01-19 14:43:53 +08:00
Chenyang Shen
6ad0a49392 Merge pull request #5300 from jumpserver/pr@dev@feat_update_facelive_check
feat: update facelive license check
2026-01-14 16:21:23 +08:00
Aaron3S
465eb45ff9 feat: update facelive license check 2026-01-14 16:16:20 +08:00
feng
f258b47ba6 perf: Move custom ai model 2026-01-05 16:48:31 +08:00
feng
0a8ed3c4cc perf: Ticket quick filter 2025-12-24 15:51:34 +08:00
zhaojisen
1cd1437357 Fixed: panel title show 2025-12-23 12:14:22 +08:00
zhaojisen
ef2c72b80e perf: optimism panel style 2025-12-23 12:02:45 +08:00
zhaojisen
cf3d2fff03 Fix the problem of overly long names 2025-12-23 11:44:37 +08:00
w940853815
3221e44e69 fix: Ticket remove import and add export support 2025-12-22 15:26:48 +08:00
w940853815
65706509b1 fix:Disabled assets have no audit records 2025-12-18 11:48:17 +08:00
feng
3d668502e1 perf: chat ai custom model 2025-12-12 15:18:16 +08:00
w940853815
56e07c8568 fix: Remove 'Account' option from const.js 2025-12-11 17:01:08 +08:00
w940853815
c2f7a9e8e2 feat: Implement secret readability control based on system settings 2025-12-11 16:42:43 +08:00
w940853815
f0949f0e54 feat: Add permission check for reading account secrets based on system settings 2025-12-11 16:42:43 +08:00
w940853815
a165e45937 perf: Include 'id' in search and filter fields for AutomationExecution 2025-12-11 14:47:58 +08:00
zhaojisen
6350bdb42d Fixed: Fix the issue where the remote application details page is lost and the account needs to be regenerated 2025-12-10 17:31:49 +08:00
w940853815
4ecaee36f9 fix: Remove unused relevant_system_user option from BaseTicketList 2025-12-09 14:41:52 +08:00
w940853815
43e7e5cd74 fix: Remove unused CAS_CREATE_USER attribute from options 2025-12-04 17:40:54 +08:00
Bai
4332dbcc1c feat: add access token page 2025-12-01 17:54:55 +08:00
jiangweidong
a755b2ffa0 perf: increase joint camp areas 2025-12-01 10:56:32 +08:00
jiangweidong
d391592778 feat: Host cloud sync supports state cloud 2025-12-01 10:56:32 +08:00
feng
3dd199ef01 fix: Ticket comment not display 2025-11-20 14:39:32 +08:00
w940853815
20e1c833a6 perf: Update asset detection logic in AccountRiskList for improved menu display 2025-11-20 10:32:05 +08:00
feng
f2c7a6bc71 perf: Account bulk error prompt 2025-11-19 17:38:52 +08:00
w940853815
6063e03d89 perf: Enhance error message handling for nested plain objects in getErrorResponseMsg 2025-11-19 15:42:26 +08:00
zhaojisen
e2d9eb5bae Fixed: Fix the issue where the global organization text is not displayed completely in the organization dropdown. 2025-11-19 15:31:10 +08:00
w940853815
84caf35f67 fix: Ensure progress display is shown correctly during job execution 2025-11-19 15:10:57 +08:00
zhaojisen
1d7a1bfff1 Fixed: Fix the issue where creating an SSH public key for a third-party user redirects to the login password tab. 2025-11-18 18:34:04 +08:00
w940853815
9039f572ac fix: Click Review to enter comments, and the page will be dimmed 2025-11-18 16:43:50 +08:00
w940853815
7798324a4b perf: Add support for error message extraction from plain objects in getErrorResponseMsg 2025-11-18 15:45:40 +08:00
feng
8e69206cfb fix: Account push show params 2025-11-17 17:29:44 +08:00
w940853815
338706247a perf: Add condition to check node type in AccountRiskList for asset detection 2025-11-17 11:15:53 +08:00
w940853815
2ae3e06484 perf: Refactor error handling and improve parameter assignment in job forms 2025-11-17 10:55:47 +08:00
w940853815
c1dcea1b29 perf: Improve error message formatting for array of strings 2025-11-12 16:22:44 +08:00
w940853815
59adc54f2d perf: Enhance AccountFormatter with options to exclude accounts 2025-11-11 18:55:34 +08:00
w940853815
afeafcbf49 perf: Job execution detail content add text-overflow class 2025-11-10 16:54:45 +08:00
w940853815
4e23107a21 perf: Support batch import of leak passwords 2025-11-06 18:36:40 +08:00
ibuler
3e267d07c1 perf: small size some png 2025-11-05 18:19:09 +08:00
fit2bot
7df6854a65 perf: upgrade vue version (#5260)
* perf: upgrade vue version

* perf: Update Dockerfile with new base image tag

---------

Co-authored-by: zhaojisen <1301338853@qq.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-11-05 17:36:47 +08:00
w940853815
4db8edce98 perf: Add confirmation dialog before syncing platform protocols 2025-11-04 15:09:30 +08:00
feng
8d69418613 perf: Bulk account support node 2025-10-31 17:19:11 +08:00
w940853815
2d798053b3 perf: Translate select assets 2025-10-31 10:35:56 +08:00
ibuler
e48385c70e perf: revert keyword to search 2025-10-30 16:27:40 +08:00
fit2bot
4ed529bbfb perf: remove sub mod (#5254)
* perf: remove sub mod

* perf: Update Dockerfile with new base image tag

---------

Co-authored-by: ibuler <ibuler@qq.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-10-30 15:23:58 +08:00
fit2bot
ca5350cc96 perf: update lodash version 2025-10-30 14:09:50 +08:00
w940853815
9046245cdb perf: Add header to file uploader with clear selection 2025-10-28 18:50:07 +08:00
fit2bot
991a512e85 perf: Optimize form uniqueness validation (#5250)
* perf: Optimize form uniqueness validation

* perf: Add some comments

* perf: check logical

---------

Co-authored-by: zhaojisen <1301338853@qq.com>
2025-10-28 16:41:49 +08:00
dependabot[bot]
6c008e3879 chore(deps): bump dompurify from 3.1.6 to 3.2.4
Bumps [dompurify](https://github.com/cure53/DOMPurify) from 3.1.6 to 3.2.4.
- [Release notes](https://github.com/cure53/DOMPurify/releases)
- [Commits](https://github.com/cure53/DOMPurify/compare/3.1.6...3.2.4)

---
updated-dependencies:
- dependency-name: dompurify
  dependency-version: 3.2.4
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-27 15:25:17 +08:00
zhaojisen
d16fbc3b13 Fixed: Fix ESLint errors 2025-10-27 14:38:12 +08:00
fit2bot
a0354e30c7 perf: org select style 2025-10-27 12:04:31 +08:00
mikebofs
0661bb0ea0 perf: all assets can add to zone 2025-10-24 10:39:09 +08:00
ibuler
e72fe04525 perf: add stat load helptip 2025-10-24 10:38:30 +08:00
feng
59cec3d6a9 perf: getDrawerTitle 2025-10-24 10:36:58 +08:00
w940853815
829f4ceaa4 fix: Replace alert with console.log for error handling 2025-10-22 18:22:51 +08:00
w940853815
b615e35e49 fix: Update help message rendering to use v-html for proper display 2025-10-22 14:59:55 +08:00
w940853815
cda282ac6b fix: Details page does not display labels. 2025-10-20 10:35:02 +08:00
w940853815
f2d44a2fd1 perf: Enhance email report success feedback with response message 2025-10-16 11:24:58 +08:00
w940853815
52f3ba012b perf: Hide vertical overflow in terminal display for improved UI 2025-10-16 10:11:32 +08:00
Chenyang Shen
d43e6a19bf Merge pull request #5236 from jumpserver/pr@dev@feat_add_tip_for_data_masking_form
feat: add fields tip for data masking form
2025-10-15 19:35:48 +08:00
Aaron3S
1f628e0d40 feat: add fields tip for data masking form 2025-10-15 19:33:47 +08:00
Chenyang Shen
9922a495eb Merge pull request #5235 from jumpserver/pr@dev@feat_update_column_show
feat: update data masking column show
2025-10-15 16:52:14 +08:00
Aaron3S
ae7549a00d feat: update data masking column show 2025-10-15 16:50:34 +08:00
Chenyang Shen
a5e870035e Merge pull request #5234 from jumpserver/pr@dev@feat_data_masking_license
feat: datamasking require license
2025-10-15 16:17:20 +08:00
Aaron3S
38f1ab3075 feat: datamasking require license 2025-10-15 16:15:10 +08:00
feng
c05248a1ab perf: Del remote account 2025-10-15 15:22:58 +08:00
w940853815
efacae517a perf: Add success message on successful update of system message subscription 2025-10-15 10:16:34 +08:00
Chenyang Shen
70b71a44d3 Merge pull request #5230 from jumpserver/pr@dev@feat_data_masking_detail
feat: add detail for data masking
2025-10-14 18:04:03 +08:00
Aaron3S
0ac220341e feat: add detail for data masking 2025-10-14 18:02:21 +08:00
w940853815
fc8fd2c8eb perf:Risk detection: When operating assets in batch, there is no prompt that the task is running 2025-10-14 16:49:39 +08:00
Chenyang Shen
f575eaafb6 Merge pull request #5228 from jumpserver/pr@dev@feat_change_some_translate
feat: change some translate
2025-10-14 16:05:06 +08:00
Aaron3S
2f79134023 feat: change some translate 2025-10-14 15:58:19 +08:00
feng
c59e6268b3 perf: remve chat fa-arrows-alt 2025-10-14 14:54:26 +08:00
w940853815
3344e01a9c perf: Asset selection optimization 2025-10-13 15:58:21 +08:00
zhaojisen
0a42031220 Fixed: Fix the issue where updating the SSH public key incorrectly redirects to a page. 2025-10-13 11:21:48 +08:00
feng
686e48f273 perf: Translate 2025-10-11 15:22:12 +08:00
w940853815
f16830adfe fix: In rule selection, the global organization will display all assets and users. 2025-10-11 10:52:51 +08:00
Chenyang Shen
be8d09b777 Merge pull request #5221 from jumpserver/pr@dev@feat_update_menu_name
feat: update menu name
2025-10-11 00:03:48 +08:00
Aaron3S
5ed2b6d9c8 feat: update menu name 2025-10-11 00:01:06 +08:00
feng
ece3ebc6e9 perf: Global can update and create ssh key 2025-10-09 18:01:55 +08:00
Aaron3S
1afd8dc934 feat: data masking 2025-10-09 10:39:05 +08:00
feng
a239060798 perf: Open web ui 2025-09-25 15:53:35 +08:00
w940853815
05032d6c78 perf: Remove useless code 2025-09-25 15:34:35 +08:00
w940853815
9dc35a603e perf: File transfer select asset component replacement 2025-09-25 15:34:35 +08:00
w940853815
43448aa482 perf: Style adjustment 2025-09-25 15:34:35 +08:00
w940853815
8887e98249 perf: Group platform 2025-09-25 15:34:35 +08:00
w940853815
43e4dcd760 perf: User checkbox select 2025-09-25 15:34:35 +08:00
w940853815
94d4be7555 perf: User checkbox select 2025-09-25 15:34:35 +08:00
w940853815
8210e2810f perf: Optimize the asset selection method of Adhoc 2025-09-25 15:34:35 +08:00
w940853815
05be6876f3 perf: Optimize file upload progress bar display 2025-09-22 17:39:01 +08:00
zhaojisen
38f8d88cdf Fixed: Fix the issue of incorrect form error messages 2025-09-22 14:14:43 +08:00
feng
3b0def17d7 perf: Translate 2025-09-22 11:21:24 +08:00
w940853815
57b0fa0b0e perf: Community edition hide report export button 2025-09-19 15:34:53 +08:00
w940853815
9611eb9c73 fix: Improve chart management by using a global _echarts object for tracking active charts 2025-09-17 19:02:24 +08:00
w940853815
a2bbb6555b fix: Optimize data fetching in AccountSummary and UserAssetActivity components 2025-09-17 18:01:03 +08:00
zhaojisen
ddd25208d8 Fixed: Fix the issue where error message prompts are being obscured. 2025-09-17 17:48:08 +08:00
w940853815
fe8db5831b fix: Edit template onPerformError error 2025-09-17 16:26:54 +08:00
feng
0c29ade399 perf: Compatible v3 ssh_key_change_strategy 2025-09-17 14:32:40 +08:00
zhaojisen
f8b2840d89 Fixed: Restore component update component settings logic 2025-09-17 14:11:40 +08:00
zhaojisen
52a18c3c35 Fixed: Fix the error reporting issue in risk detection review 2025-09-17 10:35:49 +08:00
w940853815
ace9cdcd68 perf: Translate msg template 2025-09-16 19:14:22 +08:00
w940853815
7098c2266e fix: Copy name field failed 2025-09-16 17:56:11 +08:00
w940853815
58d3489c33 fix: There is something wrong with the format of the site message 2025-09-16 17:56:11 +08:00
w940853815
396d20f31e fix: Remove priority fields in ACL components 2025-09-16 17:46:21 +08:00
zhaojisen
c8b866412a Fixed: Restore the logic for adding gateway lists 2025-09-16 17:33:13 +08:00
feng
63b163e382 perf: Translate 2025-09-16 16:14:46 +08:00
zhaojisen
e1acc642ca perf: Optimize the way connection methods are displayed in the table. 2025-09-16 11:35:45 +08:00
w940853815
e3f4cc68d2 fix: Export report pdf failed 2025-09-15 18:48:24 +08:00
w940853815
983aff62f2 fix: Update account existence check 2025-09-15 17:52:26 +08:00
zhaojisen
26e1ffdbdd Fixed: Fix Dashboard export issue on the Audit Workbench 2025-09-15 17:25:51 +08:00
zhaojisen
2002519f30 Fixed: Fix the issue of storage failure when updating components. 2025-09-15 14:40:58 +08:00
zhaojisen
c8f3e71d2c Fixed: Fixed the issue of failing to add a gateway in domain details. 2025-09-15 14:22:30 +08:00
w940853815
bd8f21e17a perf: Init template name 2025-09-12 18:32:13 +08:00
w940853815
0981b1854b perf: Remember select template 2025-09-12 18:32:13 +08:00
w940853815
94ab823b50 fix: Trim whitespace in email template content 2025-09-12 18:32:13 +08:00
w940853815
b378f41c07 fix: vue el-autocomplete flashes 2025-09-12 16:39:35 +08:00
zhaojisen
6cce077441 Confirm dialog for new announcement content 2025-09-11 17:11:40 +08:00
ibuler
361e522c5e perf: tag input min width 2025-09-11 16:53:26 +08:00
w940853815
08161c892e fix: LineChart component error 2025-09-11 15:09:05 +08:00
ibuler
39e4fdf40c perf: 优化 action btn 的大小 2025-09-11 15:03:37 +08:00
w940853815
11011f6b68 fix: Modify Dialog components import 2025-09-11 14:51:34 +08:00
mikebofs
7eb2e08f03 perf: add search place holder 2025-09-10 18:18:47 +08:00
w940853815
7d422bea51 perf: And license validation in msg template page 2025-09-10 17:24:58 +08:00
feng
3367ec624c perf: Ticket not display comment 2025-09-10 17:07:55 +08:00
fit2bot
091db8e6aa feat: setting email template content (#5173)
* feat: setting email template content

* perf: template list

* perf: show variable help text

* perf: custom template render to string

* perf: help text

* perf: update email template variable structure and improve formatting

* perf: Template content reset

* perf: typo MsgTemplate

* fix: email page error

* fix: package.json conflict

* perf: Update Dockerfile with new base image tag

---------

Co-authored-by: w940853815 <940853815@qq.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-09-10 16:49:14 +08:00
feng
5d0f2c5c60 perf: Message zIndex 20000 2025-09-09 15:09:20 +08:00
feng
71b9e87786 perf: Update mysql db_name not required 2025-09-09 11:09:14 +08:00
fit2bot
ae0b3572f8 perf: Complete the search (#5175)
* perf: global search

* perf: Update Dockerfile with new base image tag

* perf: 完成基本搜索

* perf: show search direct

* perf: change search style

* perf: 优化 panel 格式,不再用 select

* perf: search add route

* perf: add route search

* perf: change view

* perf: add to body

* perf: 再次优化格式

* perf: 优化了一些显示

* perf: 基本完成搜索功能

* perf: 完成搜索

* perf: Update Dockerfile with new base image tag

* perf: merge with remote

---------

Co-authored-by: mikebofs <mikebofs@gmail.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: ibuler <ibuler@qq.com>
2025-09-05 17:23:37 +08:00
fit2bot
217a09ebd6 perf: global search (#5171)
* perf: global search

* perf: Update Dockerfile with new base image tag

* perf: 完成基本搜索

* perf: show search direct

* perf: change search style

* perf: 优化 panel 格式,不再用 select

* perf: search add route

* perf: add route search

* perf: change view

---------

Co-authored-by: ibuler <ibuler@qq.com>
2025-09-05 16:39:37 +08:00
w940853815
ca61a75997 perf: refine layout of card body to avoid affecting el-progress 2025-09-01 10:09:19 +08:00
ibuler
3310459b2c perf: reports menus 2025-08-28 15:08:20 +08:00
w940853815
b000ca46c9 perf: update event handler from rendered to finished in Echart component 2025-08-26 16:23:23 +08:00
mikebofs
36bdf6db2b perf: echarts to components 2025-08-26 16:23:23 +08:00
mikebofs
5f20a79c0a perf: support exclude some account on permission 2025-08-26 14:58:24 +08:00
zhaojisen
67eee7bb45 Fixed: Fix the issue where the number of exported items does not match the number of items selected. 2025-08-25 16:45:17 +08:00
feng
4b54c07a42 perf: Report menu perm 2025-08-22 18:51:32 +08:00
feng626
c907e158eb Merge pull request #5152 from jumpserver/pr@dev@dashboard_export
perf: export dashboard
2025-08-22 17:57:54 +08:00
feng626
7a7d41803c Merge branch 'dev' into pr@dev@dashboard_export 2025-08-22 17:57:19 +08:00
feng
b9604a6d02 perf: report perm 2025-08-22 17:50:32 +08:00
mikebofs
794b612b8b perf: change echarts define 2025-08-22 15:26:56 +08:00
mikebofs
8a965daa39 perf: remove line chart 2025-08-22 15:15:14 +08:00
mikebofs
c0705e72e3 perf: export dashboard 2025-08-22 14:42:04 +08:00
wrd
d755fd37bd fix: Account automation report show error 2025-08-21 22:18:36 +08:00
mikebofs
ed8e6b479f stash it 2025-08-21 18:25:18 +08:00
mikebofs
c42e922d36 merge: with remote 2025-08-21 16:30:29 +08:00
mikebofs
fd7e32bbbd perf: export dashboard 2025-08-21 15:30:37 +08:00
400 changed files with 10148 additions and 6995 deletions

View File

@@ -294,7 +294,8 @@ module.exports = {
],
skipIfMatch: [
'http://[^s]*',
'^[-\\w]+/[-\\w\\.]+$' // For import paths
'^[-\\w]+/[-\\w\\.]+$',
String.raw`^\/api\/[a-z0-9\/._-]+$`,
],
minLength: 3
}

57
.prettierignore Normal file
View File

@@ -0,0 +1,57 @@
# Dependencies
node_modules/
dist/
build/
lina/
# Logs
*.log
logs/
# Runtime data
pids/
*.pid
*.seed
# Coverage directory used by tools like istanbul
coverage/
# Generated files
*.min.js
*.min.css
# Package files
*.tgz
*.tar.gz
# Lock files
package-lock.json
yarn.lock
# Build outputs
*.map
# Config files that shouldn't be formatted
.eslintrc.js
babel.config.js
jest.config.js
vue.config.js
postcss.config.js
# Theme files
src/styles/fonts/
public/fonts/
lina/fonts/
# Assets
src/assets/
public/
# Mock data
mock/
# Test files
tests/
# Documentation
*.md

View File

@@ -1,11 +0,0 @@
{
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"singleQuote": true,
"semi": false,
"trailingComma": "none",
"bracketSpacing": true,
"arrowParens": "avoid",
"endOfLine": "lf"
}

View File

@@ -1,4 +1,4 @@
FROM jumpserver/lina-base:20250805_081024 AS stage-build
FROM jumpserver/lina-base:20260114_045651 AS stage-build
ARG VERSION
ENV VERSION=$VERSION

76
PRETTIER.md Normal file
View File

@@ -0,0 +1,76 @@
# Prettier 配置说明
本项目已配置 Prettier 代码格式化工具,**仅在保存时自动格式化**,不进行批量格式化,以保持现有代码风格。
## 配置文件
- `.prettierrc` - Prettier 配置文件
- `.prettierignore` - 忽略格式化的文件列表
- `.vscode/settings.json` - VSCode 编辑器配置(保存时自动格式化)
- `.vscode/extensions.json` - 推荐的 VSCode 扩展
## 使用方法
### 1. 安装依赖
项目已安装以下依赖:
- `prettier@^2.8.8` - Prettier 核心
- `eslint-plugin-prettier@^3.1.4` - ESLint 与 Prettier 集成
- `eslint-config-prettier@^6.15.0` - 禁用与 Prettier 冲突的 ESLint 规则
### 2. 命令行使用
```bash
# ESLint 检查和修复
npm run fix
```
**注意**:本项目配置为仅在保存时自动格式化,不提供批量格式化命令。
### 3. VSCode 编辑器配置
确保安装了推荐的扩展:
- Prettier - Code formatter (esbenp.prettier-vscode)
- ESLint (dbaeumer.vscode-eslint)
- Vetur (octref.vetur)
配置已设置为保存时自动格式化。
### 4. Git 提交钩子
项目使用 `husky``lint-staged` 在提交时进行代码检查:
- 提交时运行 ESLint 检查和修复
- 不进行批量格式化,保持原有代码风格
## Prettier 配置说明
```json
{
"semi": false, // 不使用分号
"singleQuote": true, // 使用单引号
"tabWidth": 0, // 不使用缩进
"useTabs": false, // 使用空格而不是制表符
"trailingComma": "none", // 不使用尾随逗号
"printWidth": 100, // 行宽 100 字符
"bracketSpacing": true, // 对象括号内有空格
"arrowParens": "avoid", // 箭头函数单参数时不使用括号
"endOfLine": "lf", // 使用 LF 换行符
"vueIndentScriptAndStyle": false // Vue 文件中 script 和 style 标签不缩进
}
```
## 常见问题
### Q: 如何临时禁用格式化?
A: 使用注释:
```javascript
// prettier-ignore
const uglyCode = {
a:1,b:2
}
```
### Q: 如何添加文件到忽略列表?
A: 编辑 `.prettierignore` 文件,添加文件或目录路径。
### Q: VSCode 保存时没有自动格式化?
A: 检查是否安装了 Prettier 扩展,并确认 `.vscode/settings.json` 配置正确。

View File

@@ -1,150 +1,145 @@
{
"name": "lina",
"version": "v4.0.0",
"description": "JumpServer Web UI",
"author": "JumpServer Team <support@lxware.hk>",
"license": "GPL-3.0-or-later",
"scripts": {
"dev": "NODE_OPTIONS=--openssl-legacy-provider vue-cli-service serve",
"serve": "NODE_OPTIONS=--openssl-legacy-provider vue-cli-service serve",
"build": "NODE_OPTIONS=--openssl-legacy-provider vue-cli-service build",
"build:prod": "vue-cli-service build",
"build:stage": "vue-cli-service build --mode staging",
"preview": "node build/index.js --preview",
"lint": "eslint --ext .js,.vue src",
"fix": "eslint --ext .js,.vue --fix src",
"test:unit": "jest --clearCache && vue-cli-service test:unit",
"test:ci": "npm run lint && npm run test:unit",
"svgo": "svgo -f src/icons/svg --config=src/icas/svgo.yml",
"vue-i18n-extract": "vue-i18n-extract",
"vue-i18n-report": "vue-i18n-extract report -v './src/**/*.?(js|vue)' -l './src/i18n/langs/**/*.json'",
"vue-i18n-report-json": "vue-i18n-extract report -v './src/**/*.?(js|vue)' -l './src/i18n/langs/**/*.json' -o /tmp/abc.json",
"vue-i18n-report-add-miss": "vue-i18n-extract report -v './src/**/*.?(js|vue)' -l './src/i18n/langs/**/*.json' -a",
"diff-i18n": "python ./src/i18n/langs/i18n-util.py diff en ja zh_Hant",
"apply-i18n": "python ./src/i18n/langs/i18n-util.py apply en ja zh_Hant"
},
"dependencies": {
"@babel/plugin-proposal-optional-chaining": "^7.13.12",
"@fontsource/open-sans": "^5.0.24",
"@traptitech/markdown-it-katex": "^3.6.0",
"@ztree/ztree_v3": "3.5.44",
"axios": "0.28.0",
"axios-retry": "^3.1.9",
"caniuse-lite": "^1.0.30001642",
"cron-parser": "^4.0.0",
"crypto-js": "^4.1.1",
"css-color-function": "^1.3.3",
"decimal.js": "^10.4.3",
"deepmerge": "^4.2.2",
"dompurify": "^3.1.6",
"echarts": "4.7.0",
"element-ui": "^2.15.14",
"elementui-lts": "^2.16.0",
"eslint-plugin-html": "^6.0.0",
"highlight.js": "^11.9.0",
"install": "^0.13.0",
"jquery": "^3.6.1",
"js-cookie": "2.2.0",
"jsencrypt": "^3.2.1",
"less": "^3.10.3",
"less-loader": "^5.0.0",
"lodash": "^4.17.21",
"lodash.clonedeep": "^4.5.0",
"lodash.frompairs": "^4.0.1",
"lodash.get": "^4.4.2",
"lodash.has": "^4.5.2",
"lodash.includes": "^4.3.0",
"lodash.isempty": "^4.4.0",
"lodash.isequal": "^4.5.0",
"lodash.isplainobject": "^4.0.6",
"lodash.set": "^4.3.2",
"lodash.topairs": "^4.3.0",
"lodash.values": "^4.3.0",
"markdown-it": "^13.0.2",
"markdown-it-link-attributes": "^4.0.1",
"moment": "^2.29.4",
"moment-parseformat": "^4.0.0",
"normalize.css": "7.0.0",
"npm": "^7.8.0",
"nprogress": "0.2.0",
"path-to-regexp": "3.3.0",
"sortablejs": "^1.15.6",
"v-sanitize": "^0.0.13",
"vue": "2.6.10",
"vue-codemirror": "4.0.6",
"vue-cookie": "^1.1.4",
"vue-echarts": "^5.0.0-beta.0",
"vue-i18n": "^8.15.5",
"vue-json-editor": "^1.4.3",
"vue-markdown": "^2.2.4",
"vue-password-strength-meter": "^1.7.2",
"vue-router": "3.0.6",
"vue-select": "^3.9.5",
"vuejs-logger": "^1.5.4",
"vuex": "3.1.0",
"watermark-js-plus": "^1.5.8",
"xss": "^1.0.14",
"xterm": "^4.5.0",
"xterm-addon-fit": "^0.3.0",
"zxcvbn": "^4.4.2"
},
"devDependencies": {
"@babel/core": "7.18.6",
"@babel/register": "7.0.0",
"@vue/cli-plugin-babel": "3.6.0",
"@vue/cli-plugin-eslint": "^3.9.1",
"@vue/cli-plugin-unit-jest": "3.6.3",
"@vue/cli-service": "3.6.0",
"@vue/test-utils": "1.0.0-beta.29",
"autoprefixer": "^9.5.1",
"babel-core": "7.0.0-bridge.0",
"babel-eslint": "10.0.1",
"babel-jest": "23.6.0",
"chalk": "2.4.2",
"compression-webpack-plugin": "^6.1.1",
"connect": "3.6.6",
"deasync": "^0.1.29",
"eslint": "^5.15.3",
"eslint-plugin-spellcheck": "^0.0.20",
"eslint-plugin-vue": "5.2.2",
"eslint-plugin-vue-i18n": "^0.3.0",
"github-markdown-css": "^5.1.0",
"html-webpack-plugin": "3.2.0",
"husky": "^4.2.3",
"less-loader": "^5.0.0",
"lint-staged": "^10.1.2",
"mockjs": "1.0.1-beta3",
"pretty-bytes": "^5.6.0",
"runjs": "^4.3.2",
"sass": "~1.32.6",
"sass-loader": "^7.1.0",
"script-ext-html-webpack-plugin": "2.1.3",
"script-loader": "0.7.2",
"serve-static": "^1.16.0",
"strip-ansi": "^7.1.0",
"svg-sprite-loader": "4.1.3",
"svgo": "1.2.2",
"vue-i18n-extract": "^1.1.1",
"vue-template-compiler": "2.6.10"
},
"engines": {
"node": ">=8.9",
"npm": ">= 3.0.0"
},
"browserslist": [
"> 1%",
"last 4 versions",
"ie 11"
],
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"src/**/*.{js,vue}": [
"eslint --fix"
]
},
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
"name": "lina",
"version": "v4.0.0",
"description": "JumpServer Web UI",
"author": "JumpServer Team <support@lxware.hk>",
"license": "GPL-3.0-or-later",
"scripts": {
"dev": "NODE_OPTIONS=--openssl-legacy-provider vue-cli-service serve",
"serve": "NODE_OPTIONS=--openssl-legacy-provider vue-cli-service serve",
"build": "NODE_OPTIONS=--openssl-legacy-provider vue-cli-service build",
"build:prod": "vue-cli-service build",
"build:stage": "vue-cli-service build --mode staging",
"preview": "node build/index.js --preview",
"lint": "eslint --ext .js,.vue src",
"fix": "eslint --ext .js,.vue --fix src",
"test:unit": "jest --clearCache && vue-cli-service test:unit",
"test:ci": "npm run lint && npm run test:unit",
"svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml",
"vue-i18n-extract": "vue-i18n-extract",
"vue-i18n-report": "vue-i18n-extract report -v './src/**/*.?(js|vue)' -l './src/i18n/langs/**/*.json'",
"vue-i18n-report-json": "vue-i18n-extract report -v './src/**/*.?(js|vue)' -l './src/i18n/langs/**/*.json' -o /tmp/abc.json",
"vue-i18n-report-add-miss": "vue-i18n-extract report -v './src/**/*.?(js|vue)' -l './src/i18n/langs/**/*.json' -a",
"diff-i18n": "python ./src/i18n/langs/i18n-util.py diff en ja zh_Hant",
"apply-i18n": "python ./src/i18n/langs/i18n-util.py apply en ja zh_Hant"
},
"dependencies": {
"@babel/plugin-proposal-optional-chaining": "^7.13.12",
"@fontsource/open-sans": "^5.0.24",
"@kangc/v-md-editor": "^1.7.12",
"@traptitech/markdown-it-katex": "^3.6.0",
"@ztree/ztree_v3": "3.5.44",
"axios": "0.28.0",
"axios-retry": "^3.1.9",
"babel-loader": "^10.0.0",
"cache-loader": "^4.1.0",
"caniuse-lite": "^1.0.30001642",
"cron-parser": "^4.0.0",
"crypto-js": "^4.1.1",
"css-color-function": "^1.3.3",
"decimal.js": "^10.4.3",
"deepmerge": "^4.2.2",
"dompurify": "^3.2.4",
"echarts": "4.7.0",
"element-ui": "https://github.com/jumpserver-dev/element/releases/download/v2.15.15/jumpserver-element-ui-2.15.15.tgz",
"eslint-plugin-html": "^6.0.0",
"highlight.js": "^11.9.0",
"install": "^0.13.0",
"jquery": "^3.6.1",
"js-cookie": "2.2.0",
"jsencrypt": "^3.2.1",
"less": "^3.10.3",
"less-loader": "^5.0.0",
"lodash": "^4.17.21",
"markdown-it": "^13.0.2",
"markdown-it-link-attributes": "^4.0.1",
"moment": "^2.29.4",
"moment-parseformat": "^4.0.0",
"normalize.css": "7.0.0",
"npm": "^7.8.0",
"nprogress": "0.2.0",
"path-to-regexp": "3.3.0",
"sortablejs": "^1.15.6",
"v-sanitize": "^0.0.13",
"vue": "2.7.16",
"vue-codemirror": "4.0.6",
"vue-cookie": "^1.1.4",
"vue-echarts": "^5.0.0-beta.0",
"vue-i18n": "^8.15.5",
"vue-json-editor": "^1.4.3",
"vue-markdown": "^2.2.4",
"vue-password-strength-meter": "^1.7.2",
"vue-router": "3.0.6",
"vue-select": "^3.9.5",
"vuejs-logger": "^1.5.4",
"vuex": "3.1.0",
"watermark-js-plus": "^1.5.8",
"xss": "^1.0.14",
"xterm": "^4.5.0",
"xterm-addon-fit": "^0.3.0",
"zxcvbn": "^4.4.2"
},
"devDependencies": {
"@babel/core": "7.18.6",
"@babel/register": "7.0.0",
"@vue/cli-plugin-babel": "3.6.0",
"@vue/cli-plugin-eslint": "^3.9.1",
"@vue/cli-plugin-unit-jest": "3.6.3",
"@vue/cli-service": "3.6.0",
"@vue/test-utils": "1.0.0-beta.29",
"autoprefixer": "^9.5.1",
"babel-core": "6.26.3",
"babel-eslint": "10.0.1",
"babel-jest": "23.6.0",
"chalk": "2.4.2",
"compression-webpack-plugin": "^6.1.1",
"connect": "3.6.6",
"deasync": "^0.1.29",
"eslint": "^5.15.3",
"eslint-config-prettier": "^6.15.0",
"eslint-plugin-prettier": "^3.4.1",
"eslint-plugin-spellcheck": "^0.0.20",
"eslint-plugin-vue": "5.2.2",
"eslint-plugin-vue-i18n": "^0.3.0",
"github-markdown-css": "^5.1.0",
"html-webpack-plugin": "3.2.0",
"husky": "^4.2.3",
"less-loader": "^5.0.0",
"lint-staged": "^10.1.2",
"mockjs": "1.0.1-beta3",
"prettier": "^3.6.2",
"pretty-bytes": "^5.6.0",
"runjs": "^4.3.2",
"sass": "~1.32.6",
"sass-loader": "^7.1.0",
"script-ext-html-webpack-plugin": "2.1.3",
"script-loader": "0.7.2",
"serve-static": "^1.16.0",
"strip-ansi": "^7.1.0",
"svg-sprite-loader": "4.1.3",
"svgo": "1.2.2",
"vue-i18n-extract": "^1.1.1",
"vue-template-compiler": "2.7.16",
"webpack": "^4.28.4"
},
"engines": {
"node": ">=12",
"npm": ">= 3.0.0"
},
"browserslist": [
"> 1%",
"last 4 versions",
"ie 11"
],
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"src/**/*.{js,vue}": [
"eslint --fix"
]
},
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
}

View File

@@ -61,13 +61,14 @@ export function stopJob(form) {
})
}
export function JobUploadFile(form) {
export function JobUploadFile(form, config = {}) {
return request({
url: '/api/v1/ops/jobs/upload/',
method: 'post',
headers: { 'Content-Type': 'multipart/form-data' },
timeout: 60 * 60 * 1000,
data: form
data: form,
...config
})
}

View File

@@ -18,14 +18,14 @@ export function toggleLockSession(data) {
export function getAllCommandStorage() {
return request({
url: `/api/v1/terminal/command-storages/`,
url: '/api/v1/terminal/command-storages/',
method: 'get'
})
}
export function getAllReplayStorage() {
return request({
url: `/api/v1/terminal/replay-storages/`,
url: '/api/v1/terminal/replay-storages/',
method: 'get'
})
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 584 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 12 KiB

BIN
src/assets/img/dream_bg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 KiB

View File

@@ -15,10 +15,25 @@ export const accountFieldsMeta = (vm) => {
}
return {
nodes: {
component: Select2,
label: vm.$t('Node'),
el: {
value: [],
ajax: {
url: '/api/v1/assets/nodes/',
transformOption: (item) => {
return { label: item.full_value, value: item.id }
}
}
},
hidden: () => {
return !vm.addTemplate
}
},
assets: {
component: AssetSelect,
label: vm.$t('Asset'),
rules: [Required],
el: {
multiple: false
},
@@ -33,7 +48,7 @@ export const accountFieldsMeta = (vm) => {
get disabled() {
return vm.isDisabled
},
multiple: false,
multiple: vm.addTemplate,
ajax: {
url: '/api/v1/accounts/account-templates/',
transformOption: (item) => {

View File

@@ -63,7 +63,7 @@ export default {
encryptedFields: ['secret'],
fields: [
[this.$t('Basic'), ['name', 'username', 'privileged', 'su_from', 'su_from_username', 'template']],
[this.$t('Asset'), ['assets']],
[this.$t('Asset'), ['nodes', 'assets']],
[this.$t('Secret'), [
'secret_type', 'password', 'ssh_key', 'token',
'access_key', 'passphrase', 'api_key',

View File

@@ -93,8 +93,8 @@ export default {
iVisible = true
data = formValue
url = `/api/v1/accounts/accounts/bulk/`
if (data.assets.length === 0) {
this.$message.error(this.$tc('PleaseSelectAsset'))
if ((!data.assets || data.assets.length === 0) && (!data.nodes || data.nodes.length === 0)) {
this.$message.error(this.$tc('PleaseSelectAssetOrNode'))
return
}
}
@@ -107,6 +107,10 @@ export default {
this.$emit('add', true)
}
}).catch(error => {
if (error?.response?.data?.code === 'no_valid_assets') {
this.$message.error(error?.response?.data?.detail)
return
}
this.iVisible = true
this.handleResult(null, error)
})

View File

@@ -6,7 +6,7 @@
@confirm="closeDialog"
v-on="$listeners"
>
<el-alert style="margin-bottom: 10px" type="success">
<el-alert style="margin-bottom: 10px" type="info">
<span v-for="item of summary" :key="item.key"><b>{{ item.label }}</b>: {{ item.value }} </span>
</el-alert>
<DataTable :config="config" />
@@ -49,6 +49,10 @@ export default {
prop: 'asset',
label: this.$t('Asset')
},
{
prop: 'account',
label: this.$t('Account')
},
{
prop: 'state',
label: this.$t('Status'),

View File

@@ -62,6 +62,7 @@ import Dialog from '@/components/Dialog/index.vue'
import PasswordHistoryDialog from './PasswordHistoryDialog.vue'
import { SecretViewerFormatter } from '@/components/Table/TableFormatters'
import { encryptPassword } from '@/utils/secure'
import { mapGetters } from 'vuex'
export default {
name: 'ShowSecretInfo',
@@ -111,6 +112,9 @@ export default {
}
},
computed: {
...mapGetters({
publicSettings: 'publicSettings'
}),
secretTypeLabel() {
return this.account['secret_type'].label || 'Password'
},
@@ -146,7 +150,11 @@ export default {
})
},
showSecretDialog() {
return this.$axios.get(this.url, { disableFlashErrorMsg: true }).then((res) => {
if (!this.publicSettings.SECURITY_ACCOUNT_SECRET_READ) {
this.$message.warning(this.$tc('AccountSecretReadDisabled'))
return
}
return this.$axios.get(this.url).then((res) => {
this.secretInfo = res
this.sshKeyFingerprint = res?.spec_info?.ssh_key_fingerprint || '-'
this.showSecret = true
@@ -167,54 +175,54 @@ export default {
</script>
<style lang="scss" scoped>
.item-textarea ::v-deep .el-textarea__inner {
height: 110px;
.item-textarea ::v-deep .el-textarea__inner {
height: 110px;
}
.el-form-item {
border-bottom: 1px solid #EBEEF5;
padding: 5px 0;
margin-bottom: 0;
&:last-child {
border-bottom: none;
}
.el-form-item {
border-bottom: 1px solid #EBEEF5;
padding: 5px 0;
margin-bottom: 0;
&:last-child {
border-bottom: none;
}
::v-deep .el-form-item__label {
display: flex;
align-items: center;
justify-content: flex-start;
padding-right: 20px;
line-height: 30px;
word-break: keep-all;
overflow-wrap: break-word;
white-space: normal;
}
::v-deep .el-form-item__content {
line-height: 30px;
pre {
margin: 0;
}
}
::v-deep .el-form-item__label {
display: flex;
align-items: center;
justify-content: flex-start;
padding-right: 20px;
line-height: 30px;
word-break: keep-all;
overflow-wrap: break-word;
white-space: normal;
}
ul {
margin: 0;
}
::v-deep .el-form-item__content {
line-height: 30px;
li {
display: block;
font-size: 13px;
margin-bottom: 8px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
.title {
color: #303133;
font-weight: 500;
pre {
margin: 0;
}
}
}
ul {
margin: 0;
}
li {
display: block;
font-size: 13px;
margin-bottom: 8px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
.title {
color: #303133;
font-weight: 500;
}
}
</style>

View File

@@ -20,7 +20,7 @@
<script>
import TreeTable from '../../Table/TreeTable/index.vue'
import { setRouterQuery, setUrlParam } from '@/utils/common/index'
import { getShowCurrentAssetValue, setRouterQuery, setUrlParam } from '@/utils/common/index'
import $ from '@/utils/jquery-vendor'
export default {
@@ -160,7 +160,7 @@ export default {
return str
},
decorateRMenu() {
const show_current_asset = this.$cookie.get('show_current_asset') || '0'
const show_current_asset = getShowCurrentAssetValue(this.$cookie)
if (show_current_asset === '1') {
$('#m_show_asset_all_children_node').css('color', '#606266')
$('#m_show_asset_only_current_node').css('color', 'green')
@@ -172,6 +172,7 @@ export default {
getAssetsUrl(treeNode) {
let url = this.treeSetting?.url || this.url
const showCurrentAsset = getShowCurrentAssetValue(this.$cookie)
const setParam = (param, value, delay) => {
setTimeout(() => {
@@ -183,10 +184,12 @@ export default {
const nodeId = treeNode.meta.data.id
setParam('node_id', nodeId)
setParam('asset_id', '')
setParam('show_current_asset', showCurrentAsset)
} else if (treeNode.meta.type === 'asset') {
const assetId = treeNode.meta.data?.id || treeNode.id
setParam('node_id', '')
setParam('asset_id', assetId)
setParam('show_current_asset', showCurrentAsset)
} else if (treeNode.meta.type === 'category') {
setParam('category', treeNode.meta.category)
} else if (treeNode.meta.type === 'type') {

View File

@@ -13,6 +13,8 @@
</template>
<script>
import { BASE_URL } from '@/utils/common/index'
export default {
props: {
active: {
@@ -41,6 +43,16 @@ export default {
},
handleExpand() {
this.$emit('expand-full')
},
async openWebsite() {
let url = `${BASE_URL}/?_=${Date.now()}`
if (process.env.NODE_ENV !== 'production') {
url = url.replace('9528', '5173')
}
const newUrl = new URL(url)
window.open(newUrl.toString(), '_blank')
return url
}
}
}

View File

@@ -109,11 +109,6 @@ export default {
},
connectivity: connectivityMeta,
comment: { ...this.comment }
},
tableAttrs: {
rowClassName({ row }) {
return !row.is_active ? 'row_disabled' : ''
}
}
},
headerActions: {

View File

@@ -37,8 +37,12 @@ export default {
},
headerActions: {
hasExport: false,
hasImport: false,
hasExport: true,
hasImport: true,
importOptions: {
encryptFields: [''], // 这里不加密 password''只是为了保证数组有值
canImportUpdate: false
},
hasCreate: true,
hasSearch: true,
hasRefresh: true,

View File

@@ -25,6 +25,7 @@ export default {
},
data() {
const [key, value] = toM2MJsonParams(this.object.assets)
const org_id = this.object.org_id || this.$store.getters.currentOrg.id
return {
config: {
headerActions: {
@@ -33,7 +34,7 @@ export default {
hasExport: false
},
tableConfig: {
url: `/api/v1/assets/assets/?${key}=${value}`,
url: `/api/v1/assets/assets/?${key}=${value}&oid=${org_id}`,
columns: ['name', 'address', 'platform', 'type', 'is_active'],
columnsShow: {
min: ['name', 'address'],

View File

@@ -25,6 +25,7 @@ export default {
},
data() {
const [key, value] = toM2MJsonParams(this.object.users)
const org_id = this.object.org_id || this.$store.getters.currentOrg.id
return {
config: {
headerActions: {
@@ -33,7 +34,7 @@ export default {
hasExport: false
},
tableConfig: {
url: `/api/v1/users/users/?${key}=${value}`,
url: `/api/v1/users/users/?${key}=${value}&oid=${org_id}`,
columns: [
'name', 'username', 'email', 'groups', 'system_roles',
'org_roles', 'source', 'is_valid'

View File

@@ -13,17 +13,12 @@
v-on="$listeners"
>
<div v-if="confirmTypeRequired === 'relogin'">
<el-row :gutter="24" style="margin: 0 auto;">
<el-row :gutter="24" style="margin: 0 auto">
<el-col :md="24" :sm="24">
<el-alert
:title="$tc('ReLoginTitle')"
center
style="margin-bottom: 20px;"
type="error"
/>
<el-alert :title="$tc('ReLoginTitle')" center style="margin-bottom: 20px" type="error" />
</el-col>
</el-row>
<el-row :gutter="24" style="margin: 0 auto;">
<el-row :gutter="24" style="margin: 0 auto">
<el-col :md="24" :sm="24">
<el-button class="confirm-btn" size="mini" type="primary" @click="logout">
{{ this.$t('ReLogin') }}
@@ -32,11 +27,11 @@
</el-row>
</div>
<div v-else>
<el-row :gutter="24" style="margin: 0 auto;">
<el-row :gutter="24" style="margin: 0 auto">
<el-col :md="24" :sm="24" :span="24" class="add">
<el-select
v-model="subTypeSelected"
style="width: 100%; margin-bottom: 20px;"
style="width: 100%; margin-bottom: 20px"
@change="handleSubTypeChange"
>
<el-option
@@ -49,19 +44,22 @@
</el-select>
</el-col>
</el-row>
<el-row v-if="!noCodeMFA.includes(subTypeSelected)" :gutter="24" style="margin: 0 auto;">
<el-col :md="24" :sm="24" style="display: flex; align-items: center; ">
<el-row v-if="!noCodeMFA.includes(subTypeSelected)" :gutter="24" style="margin: 0 auto">
<el-col :md="24" :sm="24" style="display: flex; align-items: center">
<el-input
v-model="secretValue"
:placeholder="inputPlaceholder"
:show-password="showPassword"
@keyup.enter.native="handleConfirm"
/>
<span v-if="subTypeSelected === 'sms' || subTypeSelected === 'email'" style="margin: -1px 0 0 20px;">
<span
v-if="subTypeSelected === 'sms' || subTypeSelected === 'email'"
style="margin: -1px 0 0 20px"
>
<el-button
:disabled="smsBtnDisabled"
size="mini"
style="line-height: 14px; float: right;"
style="line-height: 14px; float: right"
type="primary"
@click="sendCode"
>
@@ -72,21 +70,17 @@
</el-row>
<el-row>
<el-col>
<iframe v-if="passkeyVisible" :src="passkeyUrl" style="display: none" />
<iframe
v-if="passkeyVisible"
:src="passkeyUrl"
style="display: none"
/>
<iframe
v-if="isFaceCaptureVisible && subTypeSelected ==='face' && faceCaptureUrl"
v-if="isFaceCaptureVisible && subTypeSelected === 'face' && faceCaptureUrl"
:src="faceCaptureUrl"
allow="camera"
sandbox="allow-scripts allow-same-origin"
style="width: 100%; height: 600px;border: none;"
style="width: 100%; height: 600px; border: none"
/>
</el-col>
</el-row>
<el-row :gutter="24" style="margin: 20px auto 10px;">
<el-row :gutter="24" style="margin: 20px auto 10px">
<el-col :md="24" :sm="24">
<el-button
v-if="!noCodeMFA.includes(subTypeSelected)"
@@ -195,55 +189,65 @@ export default {
this.$log.debug('perform confirm action')
const confirmType = response.data?.code
const confirmUrl = '/api/v1/authentication/confirm/'
this.$axios.get(confirmUrl, { params: { confirm_type: confirmType } }).then((data) => {
this.confirmTypeRequired = data.confirm_type
this.$axios
.get(confirmUrl, { params: { confirm_type: confirmType } })
.then(data => {
this.confirmTypeRequired = data.confirm_type
if (this.confirmTypeRequired === 'relogin') {
this.$axios.post(confirmUrl, { 'confirm_type': 'relogin', 'secret_key': 'x' }).then(() => {
this.callback()
this.visible = false
}).catch(() => {
this.title = this.$t('NeedReLogin')
this.visible = true
})
return
}
this.subTypeChoices = data.content
const defaultSubType = this.subTypeChoices.filter(item => !item.disabled)[0]
this.subTypeSelected = defaultSubType.name
this.inputPlaceholder = defaultSubType.placeholder
this.visible = true
}).catch((err) => {
const data = err.response?.data
const msg = data?.error || data?.detail || data?.msg || this.$t('GetConfirmTypeFailed')
this.$message.error(msg)
this.cancel(err)
}).finally(() => {
this.processing = false
})
if (this.confirmTypeRequired === 'relogin') {
this.$axios
.post(confirmUrl, { confirm_type: 'relogin', secret_key: 'x' })
.then(() => {
this.callback()
this.visible = false
})
.catch(() => {
this.title = this.$t('NeedReLogin')
this.visible = true
})
return
}
this.subTypeChoices = data.content
const defaultSubType = this.subTypeChoices.filter(item => !item.disabled)[0]
this.subTypeSelected = defaultSubType.name
this.inputPlaceholder = defaultSubType.placeholder
this.visible = true
})
.catch(err => {
const data = err.response?.data
const msg = data?.error || data?.detail || data?.msg || this.$t('GetConfirmTypeFailed')
this.$message.error(msg)
this.cancel(err)
})
.finally(() => {
this.processing = false
})
}, 500),
logout() {
window.location.href = `${process.env.VUE_APP_LOGOUT_PATH}?next=${this.$route.fullPath}`
},
sendCode() {
this.$axios.post(`/api/v1/authentication/mfa/select/`, { type: this.subTypeSelected }).then(res => {
this.$message.success(this.$tc('VerificationCodeSent'))
let time = 60
this.smsBtnDisabled = true
this.$axios
.post(`/api/v1/authentication/mfa/select/`, { type: this.subTypeSelected })
.then(res => {
this.$message.success(this.$tc('VerificationCodeSent'))
let time = 60
this.smsBtnDisabled = true
const interval = setInterval(() => {
time -= 1
this.smsBtnText = `${this.$t('Pending')}: ${time}`
const interval = setInterval(() => {
time -= 1
this.smsBtnText = `${this.$t('Pending')}: ${time}`
if (time <= 0) {
clearInterval(interval)
this.smsBtnText = this.$t('SendVerificationCode')
this.smsBtnDisabled = false
}
}, 1000)
}).catch(() => {
this.$message.error(this.$tc('FailedToSendVerificationCode'))
})
if (time <= 0) {
clearInterval(interval)
this.smsBtnText = this.$t('SendVerificationCode')
this.smsBtnDisabled = false
}
}, 1000)
})
.catch(() => {
this.$message.error(this.$tc('FailedToSendVerificationCode'))
})
},
handlePasskeyVerify() {
this.passkeyVisible = true
@@ -267,23 +271,26 @@ export default {
},
startFaceCapture() {
const url = '/api/v1/authentication/face/context/'
this.$axios.post(url).then(data => {
const token = data['token']
this.faceCaptureUrl = '/facelive/capture?token=' + token
this.isFaceCaptureVisible = true
this.$axios
.post(url)
.then(data => {
const token = data['token']
this.faceCaptureUrl = '/facelive/capture?token=' + token
this.isFaceCaptureVisible = true
const timer = setInterval(() => {
this.$axios.get(url + `?token=${token}`).then(data => {
if (data['is_finished']) {
clearInterval(timer)
this.isFaceCaptureVisible = false
this.handleConfirm()
}
})
}, 1000)
}).catch(() => {
this.$message.error(this.$tc('FailedToStartFaceCapture'))
})
const timer = setInterval(() => {
this.$axios.get(url + `?token=${token}`).then(data => {
if (data['is_finished']) {
clearInterval(timer)
this.isFaceCaptureVisible = false
this.handleConfirm()
}
})
}, 1000)
})
.catch(() => {
this.$message.error(this.$tc('FailedToStartFaceCapture'))
})
},
handleFaceCapture() {
this.startFaceCapture()
@@ -306,16 +313,22 @@ export default {
const data = {
confirm_type: this.confirmTypeRequired,
mfa_type: this.confirmTypeRequired === 'mfa' ? this.subTypeSelected : '',
secret_key: this.confirmTypeRequired === 'password' ? encryptPassword(this.secretValue) : this.secretValue
secret_key:
this.confirmTypeRequired === 'password'
? encryptPassword(this.secretValue)
: this.secretValue
}
this.$axios.post(`/api/v1/authentication/confirm/`, data).then(() => {
this.onSuccess()
}).catch((err) => {
this.$message.error(err.message || this.$tc('ConfirmFailed'))
this.faceCaptureUrl = null
this.isFaceCaptureVisible = false
})
this.$axios
.post(`/api/v1/authentication/confirm/`, data)
.then(() => {
this.onSuccess()
})
.catch(err => {
this.$message.error(err.message || this.$tc('ConfirmFailed'))
this.faceCaptureUrl = null
this.isFaceCaptureVisible = false
})
}
}
}

View File

@@ -0,0 +1,100 @@
<template>
<Dialog
:show-cancel="false"
:show-confirm="false"
:title="title"
:visible.sync="iVisible"
class="help-dialog"
top="1vh"
width="50%"
>
<p>{{ variablesHelpText }}</p>
<table border="1" class="help-table">
<tr>
<th>{{ $tc('Variable') }}</th>
<th>{{ $tc('Description') }}</th>
<th>{{ $tc('Example') }}</th>
</tr>
<tr v-for="(item, index) in variables" :key="index">
<td :title="$tc('ClickCopy')" class="item-td text-link" @click="onCopy(item.name)">
<label class="item-label">{{ item.name }}</label>
</td>
<td><span>{{ item.label }}</span></td>
<td><span>{{ item.default }}</span></td>
</tr>
</table>
</Dialog>
</template>
<script>
import Dialog from '@/components/Dialog/index.vue'
import { copy } from '@/utils/common/index'
export default {
components: {
Dialog
},
props: {
visible: {
type: Boolean,
default: false
},
variables: {
type: Array,
default: () => []
},
variablesHelpText: {
type: String,
default() {
return this.$t('WatermarkVariableHelpText')
}
}
},
data() {
return {
title: this.$t('BuiltinVariable')
}
},
computed: {
iVisible: {
set(val) {
this.$emit('update:visible', val)
},
get() {
return this.visible
}
}
},
methods: {
onCopy(key) {
copy(key)
}
}
}
</script>
<style lang="scss" scoped>
::v-deep .help-dialog.dialog .el-dialog__footer {
border-top: none;
padding: 8px;
}
.help-table {
width: 100%;
border-collapse: collapse;
border: 1px solid #dee2e6;
}
::v-deep .help-table th,
::v-deep .help-table td {
height: 40px;
padding: 0 8px;
text-align: left;
}
::v-deep .help-table .item-td,
::v-deep .help-table .item-label {
cursor: pointer;
color: var(--color-primary);
}
</style>

View File

@@ -5,7 +5,7 @@
<div v-if="item.has !== false" :key="item.key" :class="item.class " :label="item.key" class="el-form-item">
<span slot="label" class="el-form-item__label"> {{ formateLabel(item.key) }}</span>
<span class="item-value el-form-item__content">
<template
<component
:is="item.component"
v-if="item.component"
v-bind="{...item}"

View File

@@ -5,7 +5,7 @@
v-if="action.dropdown"
v-show="action.dropdown.length > 0"
:key="action.name"
:class="[action.name, {grouped: action.grouped }]"
:class="[action.name, { grouped: action.grouped, 'table-action-text': isTableActionText }]"
:size="action.size"
:split-button="!!action.split"
:type="action.type"
@@ -16,29 +16,32 @@
@command="handleDropdownCallback"
>
<span v-if="action.split" :style="{ cursor: action.disabled ? 'not-allowed' : 'pointer' }">
{{ action.title }}
<Icon v-if="isEllipsisAction(action)" class="ellipsis-icon" icon="fa-ellipsis-v" />
<span v-else>{{ getActionTitle(action) }}</span>
</span>
<el-button
v-else
:class="action.name"
:class="[action.name, { 'table-action-text': isTableActionText }]"
:size="size"
class="more-action"
v-bind="{...cleanButtonAction(action), icon: ''}"
v-bind="{ ...cleanButtonAction(action), icon: '' }"
>
<span class="pre-icon">
<Icon v-if="action.icon" :icon="action.icon" />
</span>
<span v-if="action.title">
{{ action.title }}<i class="el-icon-arrow-down el-icon--right" />
<Icon v-if="isEllipsisAction(action)" class="ellipsis-icon" icon="fa-ellipsis-v" />
<span v-else>{{ getActionTitle(action) }}</span>
<i class="el-icon-arrow-down el-icon--right" />
</span>
</el-button>
<el-dropdown-menu slot="dropdown" style="overflow: auto;max-height: 60vh">
<el-dropdown-menu slot="dropdown" style="overflow: auto; max-height: 60vh">
<template v-for="option in action.dropdown">
<div
v-if="option.group"
:key="'group:'+option.name"
:key="'group:' + option.name"
class="dropdown-menu-title"
style="width:130px"
style="width: 130px"
>
{{ option.group }}
</div>
@@ -54,7 +57,7 @@
:command="[option, action]"
:title="option.tip"
class="dropdown-item"
v-bind="{...option, icon: ''}"
v-bind="{ ...option, icon: '' }"
>
<span v-if="actionsHasIcon(action.dropdown)" class="pre-icon">
<Icon v-if="option.icon" :icon="option.icon" />
@@ -69,10 +72,10 @@
<el-button
v-else
:key="action.name"
:class="[action.name, {grouped: action.grouped }]"
:class="[action.name, { grouped: action.grouped, 'table-action-text': isTableActionText }]"
:size="size"
class="action-item"
v-bind="{...cleanButtonAction(action), icon: ''}"
v-bind="{ ...cleanButtonAction(action), icon: '' }"
@click="handleClick(action)"
>
<el-tooltip :content="action.tip" :disabled="!action.tip" placement="top">
@@ -80,7 +83,8 @@
<span v-if="action.icon" style="vertical-align: initial">
<Icon :icon="action.icon" />
</span>
{{ action.title }}
<Icon v-if="isEllipsisAction(action)" class="ellipsis-icon" icon="fa-ellipsis-v" />
<span v-else>{{ getActionTitle(action) }}</span>
</span>
</el-tooltip>
</el-button>
@@ -118,9 +122,21 @@ export default {
computed: {
iActions() {
return this.cleanActions(this.actions)
},
tableActionButtonType() {
return this.$store?.state?.settings?.tableActionButtonType || 'default'
},
isTableActionText() {
return this.tableActionButtonType === 'text'
}
},
methods: {
getActionTitle(action) {
return action?.title
},
isEllipsisAction(action) {
return this.isTableActionText && action?.title === '...'
},
actionsHasIcon(actions) {
return actions.some(action => action.icon)
},
@@ -228,9 +244,10 @@ export default {
<style lang="scss" scoped>
$btn-text-color: #ffffff;
$color-btn-background: #E8F7F4;
$color-btn-focus-background: #83CBBA;
$color-divided: #E4E7ED;
$color-btn-background: var(--color-primary-light-3, #e8f7f4);
$color-btn-focus-background: var(--color-primary-light-1, var(--color-primary));
$color-text-hover: var(--color-primary-light-1);
$color-divided: #e4e7ed;
$color-drop-menu-title: #909399;
$color-drop-menu-border: #e4e7ed;
@@ -258,9 +275,11 @@ $color-drop-menu-border: #e4e7ed;
.action-item.el-dropdown {
font-size: 11px;
.more-action.el-button--default {
::v-deep .el-icon-arrow-down.el-icon--right {
color: var(--color-icon-primary) !important;
.more-action {
.el-button--default {
::v-deep .el-icon-arrow-down.el-icon--right {
color: var(--color-icon-primary) !important;
}
}
}
@@ -284,6 +303,8 @@ $color-drop-menu-border: #e4e7ed;
.el-button {
padding: 2px 5px;
line-height: 1.3;
font-size: 13px;
&:not(.is-plain) {
color: $btn-text-color;
@@ -314,12 +335,29 @@ $color-drop-menu-border: #e4e7ed;
background-color: $color-btn-focus-background;
}
}
.action-item.table-action-text.el-button,
::v-deep .action-item.table-action-text.el-dropdown .el-button {
color: var(--color-primary) !important;
background-color: transparent !important;
border-color: transparent !important;
transition: color 0.2s ease;
}
.action-item.table-action-text.el-button:hover,
.action-item.table-action-text.el-button:focus,
::v-deep .action-item.table-action-text.el-dropdown .el-button:hover,
::v-deep .action-item.table-action-text.el-dropdown .el-button:focus {
color: $color-text-hover !important;
background-color: transparent !important;
border-color: transparent !important;
box-shadow: none !important;
}
}
// 下拉 options
.el-dropdown-menu {
::v-deep .more-batch-processing {
&:hover {
background-color: transparent !important;
}

View File

@@ -1,6 +1,6 @@
<template>
<div class="content">
<echarts
<div>
<Echart
ref="echarts"
:options="options"
:autoresize="true"
@@ -12,9 +12,10 @@
// eslint-disable-next-line no-unused-vars
import * as echarts from 'echarts'
import { mix } from '@/utils/theme/color'
import Echart from '@/components/Dashboard/Echart.vue'
export default {
components: {},
components: { Echart },
props: {
datesMetrics: {
type: Array,

View File

@@ -0,0 +1,71 @@
<template>
<echarts
:options="iOptions"
v-bind="$attrs"
@finished="onFinished"
v-on="$listeners"
/>
</template>
<script>
import 'echarts'
export default {
components: {},
props: {
options: {
type: Object,
required: true
}
},
data() {
const urlParams = new URLSearchParams(window.location.search)
const isExport = urlParams.get('export') === 'true'
return {
isExport: isExport
}
},
computed: {
iOptions() {
return {
...this.options,
animation: !this.isExport
}
}
},
created() {
if (!window._echarts) {
window._echarts = {
total: new Set(),
finished: new Set()
}
}
// 唯一 id避免重复计数
this._chartId = `chart_${Date.now()}_${Math.random().toString(36).slice(2)}`
window._echarts.total.add(this._chartId)
},
beforeDestroy() {
if (window._echarts) {
window._echarts.total.delete(this._chartId)
window._echarts.finished.delete(this._chartId)
// 可选:当没有图表时清理全局对象
if (window._echarts.total.size === 0) {
delete window._echarts
delete window.echartsFinished
}
}
},
methods: {
onFinished() {
if (!window._echarts) return
window._echarts.finished.add(this._chartId)
if (window._echarts.finished.size === window._echarts.total.size) {
window.echartsFinished = true
}
}
}
}
</script>
<style scoped lang="scss">
</style>

View File

@@ -1,20 +1,12 @@
<template>
<div>
<echarts
<Echart
ref="echarts"
:options="options"
:autoresize="true"
theme="light"
:class="{'disabled-when-print': !!dataUrl}"
@finished="genSnapshot"
/>
<img
v-if="dataUrl"
:src="dataUrl"
class="enabled-when-print"
style="display: none;width: 100%;"
alt="chart snapshot"
>
</div>
</template>
@@ -22,9 +14,11 @@
// eslint-disable-next-line no-unused-vars
import * as echarts from 'echarts'
import { mix } from '@/utils/theme/color'
import Echart from '@/components/Dashboard/Echart.vue'
export default {
name: 'LoginMetric',
components: { Echart },
props: {
range: {
type: String,
@@ -285,14 +279,4 @@ export default {
width: 100%;
height: 272px;
}
@media print {
.disabled-when-print {
display: none !important;
}
.enabled-when-print {
display: block !important;
width: 100% !important;
}
}
</style>

View File

@@ -1,6 +1,6 @@
<template>
<div>
<echarts
<Echart
ref="echarts"
:options="options"
:autoresize="true"
@@ -13,8 +13,10 @@
// eslint-disable-next-line no-unused-vars
import * as echarts from 'echarts'
import { mix } from '@/utils/theme/color'
import Echart from '@/components/Dashboard/Echart.vue'
export default {
components: { Echart },
props: {
colors: {
type: Array,
@@ -35,14 +37,15 @@ export default {
}
},
data() {
return {
}
return {}
},
computed: {
options() {
const seriesList = []
const labels = this.data.map(item => item.label)
const total = _.sumBy(this.data, function(i) { return i.total })
const total = _.sumBy(this.data, function(i) {
return i.total
})
for (let i = 0, len = this.data.length; i < len; i++) {
const current = this.data[i]
let num = (current.total / total) * 100
@@ -177,8 +180,8 @@ export default {
</script>
<style lang="scss" scoped>
.echarts {
width: 100%;
height: 72px;
}
.echarts {
width: 100%;
height: 72px;
}
</style>

View File

@@ -38,7 +38,7 @@ export default {
{
title: this.$t('OnlineSessions'),
body: {
route: { name: `SessionList`, params: { activeMenu: 'OnlineList' }},
route: { name: `SessionList`, params: { activeMenu: 'OnlineList' } },
count: this.counter.total_count_online_sessions,
disabled: !this.$hasPerm('terminal.view_session')
}
@@ -46,7 +46,7 @@ export default {
{
title: this.$t('CurrentConnectionUsers'),
body: {
route: { name: `SessionList`, params: { activeMenu: 'OnlineList' }},
route: { name: `SessionList`, params: { activeMenu: 'OnlineList' } },
count: this.counter.total_count_online_users,
disabled: !this.$hasPerm('terminal.view_session')
}

View File

@@ -1,6 +1,6 @@
<template>
<div>
<echarts
<Echart
ref="echarts"
:autoresize="true"
:options="options"
@@ -13,12 +13,15 @@ import 'echarts/lib/chart/line'
import 'echarts/lib/component/legend'
import Decimal from 'decimal.js'
import Echart from '@/components/Dashboard/Echart.vue'
export default {
components: { Echart },
props: {
config: {
type: Object,
default: () => {}
default: () => {
}
}
},
computed: {

View File

@@ -5,6 +5,7 @@
ref="dataForm"
:fields="totalFields"
:form="iForm"
:server-errors="serverErrors"
v-bind="$attrs"
v-on="$listeners"
>
@@ -28,6 +29,7 @@
import DataForm from '../DataForm/index.vue'
import FormGroupHeader from '@/components/Form/FormGroupHeader/index.vue'
import { FormFieldGenerator } from '@/components/Form/AutoDataForm/utils'
import { UniqueCheck } from '@/components/Form/DataForm/rules'
export default {
name: 'AutoDataForm',
@@ -65,7 +67,8 @@ export default {
totalFields: [],
loading: true,
groups: [],
errors: {}
errors: {},
serverErrors: {}
}
},
computed: {
@@ -103,6 +106,8 @@ export default {
this.generateColumns()
this.$emit('afterGenerateColumns', this.totalFields)
this.cleanFormValue()
// 初始化时清空错误
this.serverErrors = {}
this.loading = false
},
generateColumns() {
@@ -110,6 +115,47 @@ export default {
this.totalFields = generator.generateFields(this.fields, this.fieldsMeta, this.remoteMeta)
this.groups = generator.groups
this.$log.debug('Total fields: ', this.totalFields)
this.applyUniqueRules()
},
applyUniqueRules() {
const fields = this.totalFields || []
const currentIdGetter = () => {
return this.$route?.params?.id || this.form?.id || this.iForm?.id
}
// 移除 url 后拼接的参数
const defaultListUrl = (() => {
try {
const u = new URL(this.url, location.origin)
u.pathname = u.pathname.replace(/\/(\d+|[0-9a-fA-F-]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12})\/?$/, '/')
return u.origin ? u.origin + u.pathname : u.pathname
} catch (e) {
return (this.url || '').replace(/\/(\d+|[0-9a-fA-F-]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12})\/?($|\?)/, '/$2')
}
})()
fields.forEach(field => {
const conf = field?.uniqueCheck
if (!conf) return
const confObj = (typeof conf === 'object') ? conf : {}
const param = confObj.param || field.prop || field.id
const url = confObj.url || defaultListUrl
const label = confObj.label || field.label || param
const entityName = confObj.entityName || ''
if (!Array.isArray(field.rules)) field.rules = []
field.rules.push(UniqueCheck({
url,
param,
label,
entityName,
getIgnoreId: currentIdGetter,
fieldName: field.prop || field.id
}))
})
},
_cleanFormValue(form, remoteMeta) {
if (!form) {
@@ -139,15 +185,69 @@ export default {
cleanFormValue() {
this._cleanFormValue(this.iForm, this.remoteMeta)
},
setFieldError(name, error) {
error = error.replace(/[。.]+$/, '')
const field = this.totalFields.find((v) => v.prop === name)
if (!field) {
return
_getElFormInstance() {
try {
return this.$refs?.dataForm?.$refs?.form?.$refs?.elForm || null
} catch (e) {
return null
}
if (typeof error === 'string') {
field.el.errors = error
field.attrs.error = error
},
/**
* @description 仅清理 UI 的错误展示,不触发表单内容重建
*/
clearAllFieldErrors() {
const elForm = this._getElFormInstance()
if (elForm && Array.isArray(elForm.fields)) {
elForm.fields.forEach((item) => {
item.validateMessage = ''
item.validateState = ''
})
}
// 不修改 totalFields/attrs避免触发 content 重建导致输入丢失
this.serverErrors = {}
},
setFieldError(name, error) {
error = (error || '').toString().replace(/[。.]+$/, '')
const elForm = this._getElFormInstance()
if (elForm && Array.isArray(elForm.fields)) {
const item = elForm.fields.find(f => f.prop === name)
if (item) {
item.validateMessage = error
item.validateState = error ? 'error' : ''
}
}
// 不写入 totalFields避免触发 innerContent 变化导致表单值被覆盖
this.$set(this.serverErrors, name, error)
},
setErrors(errors) {
const mapped = {}
Object.entries(errors || {}).forEach(([k, v]) => {
let msg = v
console.log(k, v)
// v是数组并且数组都是字符串则拼接为字符串
if (Array.isArray(v) && v.every(item => typeof item === 'string')) msg = v.join('; ')
// 处理 [{"port":["请确保该值小于或者等于 65535。"]},{},{}] 这种情况
else if (Array.isArray(v) && v.every(item => _.isPlainObject(item))) {
const subMsg = []
v.forEach((subItem) => {
Object.values(subItem).forEach((subMsgArr) => {
if (Array.isArray(subMsgArr)) {
subMsg.push(...subMsgArr)
}
})
})
msg = subMsg.join(' ')
} else if (typeof v === 'object' && v !== null) msg = JSON.stringify(v)
mapped[k] = String(msg || '')
})
this.serverErrors = mapped
const elForm = this._getElFormInstance()
if (elForm && Array.isArray(elForm.fields)) {
elForm.fields.forEach((item) => {
const msg = mapped[item.prop] || ''
item.validateMessage = msg
item.validateState = msg ? 'error' : ''
})
}
},
groupHidden(group, i) {

View File

@@ -6,6 +6,7 @@
:prop="prop"
:rules="_show && Array.isArray(data.rules) ? data.rules : []"
v-bind="data.attrs"
:error="errorText"
>
<template v-if="data.label" #label>
<span :title="data.label">
@@ -19,7 +20,8 @@
placement="right"
popper-class="help-tips"
>
<div slot="content" v-sanitize="data.helpTip" class="help-tip-content" /> <!-- Noncompliant -->
<div slot="content" v-sanitize="data.helpTip" class="help-tip-content" />
<!-- Noncompliant -->
<i class="fa fa-question-circle-o help-tip-icon" />
</el-tooltip>
</span>
@@ -27,11 +29,7 @@
<template v-if="readonly && hasReadonlyContent">
<div
v-if="data.type === 'input'"
:style="
componentProps.type === 'textarea'
? {padding: '10px 0', lineHeight: 1.5}
: ''
"
:style="componentProps.type === 'textarea' ? { padding: '10px 0', lineHeight: 1.5 } : ''"
>
{{ itemValue }}
</div>
@@ -50,11 +48,7 @@
v-on="listeners"
>
<template v-for="opt in options">
<el-option
v-if="data.type === 'select'"
:key="opt.label"
v-bind="opt"
/>
<el-option v-if="data.type === 'select'" :key="opt.label" v-bind="opt" />
<el-checkbox-button
v-else-if="data.type === 'checkbox-group' && data.style === 'button'"
:key="opt.value"
@@ -111,10 +105,10 @@
<script>
import getEnableWhenStatus from '../util/enable-when'
import { noop } from '../util/utils'
import _get from 'lodash.get'
import _includes from 'lodash.includes'
import _topairs from 'lodash.topairs'
import _frompairs from 'lodash.frompairs'
import _get from 'lodash/get'
import _includes from 'lodash/includes'
import _topairs from 'lodash/toPairs'
import _frompairs from 'lodash/fromPairs'
function validator(data) {
if (!data) {
@@ -152,6 +146,10 @@ export default {
props: {
// eslint-disable-next-line vue/require-default-prop
data: Object,
serverErrors: {
type: Object,
default: () => ({})
},
prop: {
type: String,
default() {
@@ -170,7 +168,8 @@ export default {
data() {
return {
propsInner: {},
isBlurTrigger: this.data.rules &&
isBlurTrigger:
this.data.rules &&
this.data.rules.some(rule => {
return rule.required && rule.trigger === 'blur'
})
@@ -179,7 +178,7 @@ export default {
computed: {
// 解构运算符会处理 undefined 的情况
componentProps: ({ data: { el }, propsInner }) => ({ ...el, ...propsInner }),
hasReadonlyContent: ({ data: { type }}) => _includes(['input', 'select'], type),
hasReadonlyContent: ({ data: { type } }) => _includes(['input', 'select'], type),
hiddenStatus: ({ data: { hidden = () => false }, data, value }) => hidden(value, data),
enableWhenStatus: ({ data: { enableWhen }, value }) => getEnableWhenStatus(enableWhen, value),
// 是否显示
@@ -189,6 +188,11 @@ export default {
classes() {
return 'el-form-item-' + this.data.prop + ' ' + (this.data.attrs?.class || '')
},
errorText() {
const fromAttrs = this.data?.attrs?.error
const fromServer = this.serverErrors ? this.serverErrors[this.data.prop] : ''
return fromAttrs || fromServer || ''
},
listeners() {
const {
data: {
@@ -204,10 +208,7 @@ export default {
} = this
return {
..._frompairs(
_topairs(on).map(([eName, handler]) => [
eName,
(...args) => handler(args, updateForm)
]),
_topairs(on).map(([eName, handler]) => [eName, (...args) => handler(args, updateForm)])
),
// 手动更新表单数据
input: (value, ...rest) => {
@@ -232,9 +233,7 @@ export default {
multipleValue: ({ data, itemValue, options = [] }) => {
const multipleSelectValue =
_get(data, 'el.multiple') && Array.isArray(itemValue)
? itemValue
: [itemValue]
_get(data, 'el.multiple') && Array.isArray(itemValue) ? itemValue : [itemValue]
return multipleSelectValue
.map(val => (options.find(op => op.value === val) || {}).label)
.join()
@@ -254,8 +253,7 @@ export default {
if (v.url === oldV.url || v.request === oldV.request) return
}
const isOptionsCase =
['select', 'checkbox-group', 'radio-group'].indexOf(this.data.type) >
-1
['select', 'checkbox-group', 'radio-group'].indexOf(this.data.type) > -1
const {
url,
request = () => this.$axios.get(url).then(resp => resp.data),
@@ -323,7 +321,7 @@ export default {
}
}
</script>
<style lang='scss' scoped>
<style lang="scss" scoped>
.help-tips {
opacity: 0.8;
line-height: 2;
@@ -332,7 +330,7 @@ export default {
.help-block {
::v-deep .el-alert__icon {
font-size: 16px
font-size: 16px;
}
&.checkbox {

View File

@@ -1,11 +1,18 @@
<template>
<el-form ref="elForm" :model="value" class="el-form-renderer" v-bind="$attrs" @submit.native.prevent>
<el-form
ref="elForm"
:model="value"
class="el-form-renderer"
v-bind="$attrs"
@submit.native.prevent
>
<template v-for="item in innerContent">
<slot v-if="!isHidden(item)" :name="`id:${item.id}`" />
<component
:is="item.type === GROUP ? 'render-form-group' : 'render-form-item'"
:key="item.id"
:data="item"
:server-errors="serverErrors"
:disabled="disabled || item.disabled"
:item-value="value[item.id]"
:options="options[item.id]"
@@ -19,13 +26,19 @@
</el-form>
</template>
<script>
import _set from 'lodash.set'
import _isequal from 'lodash.isequal'
import _clonedeep from 'lodash.clonedeep'
import _set from 'lodash/set'
import _isequal from 'lodash/isEqual'
import _clonedeep from 'lodash/cloneDeep'
import RenderFormGroup from './components/render-form-group.vue'
import RenderFormItem from './components/render-form-item.vue'
import transformContent from './util/transform-content'
import { collect, correctValue, mergeValue, transformInputValue, transformOutputValue } from './util/utils'
import {
collect,
correctValue,
mergeValue,
transformInputValue,
transformOutputValue
} from './util/utils'
const GROUP = 'group'
@@ -47,6 +60,10 @@ export default {
type: Array,
required: true
},
serverErrors: {
type: Object,
default: () => ({})
},
disabled: {
type: Boolean,
default: false

View File

@@ -1,5 +1,5 @@
import _get from 'lodash.get'
import _has from 'lodash.has'
import _get from 'lodash/get'
import _has from 'lodash/has'
/**
* 处理 enableWhen
@@ -20,7 +20,5 @@ export default function getEnableWhenStatus(enableWhen, value) {
})
}
return Array.isArray(enableWhen)
? enableWhen.some(handleCondition)
: handleCondition(enableWhen)
return Array.isArray(enableWhen) ? enableWhen.some(handleCondition) : handleCondition(enableWhen)
}

View File

@@ -1,5 +1,5 @@
/* eslint-disable no-sequences */
import _kebabcase from 'lodash.kebabcase'
import _ from 'lodash'
/**
* content 的每一项会浅拷贝一层
* 只可以在 item 层新增修改属性,如 item.a = b
@@ -13,7 +13,7 @@ export default function transformContent(content) {
removeDollarInKey(item)
extractRulesFromComponent(item)
// 有些旧写法是 checkboxGroup & radioGroup
item.type = _kebabcase(item.type)
item.type = _.kebabCase(item.type)
}
return item
@@ -34,8 +34,5 @@ export function extractRulesFromComponent(item) {
if (!component || typeof component === 'string') return
const { rules = [] } = component
item.rules = [
...(item.rules || []),
...(typeof rules === 'function' ? rules(item) : rules)
]
item.rules = [...(item.rules || []), ...(typeof rules === 'function' ? rules(item) : rules)]
}

View File

@@ -1,5 +1,5 @@
import _frompairs from 'lodash.frompairs'
import _isplainobject from 'lodash.isplainobject'
import _frompairs from 'lodash/fromPairs'
import _isplainobject from 'lodash/isPlainObject'
export function noop() {}
@@ -12,11 +12,9 @@ export function collect(content, key) {
value: item.type === 'group' ? collect(item.items, key) : item[key]
}))
.filter(
({ type, value }) =>
value !== undefined ||
(type === 'group' && Object.keys(value).length),
({ type, value }) => value !== undefined || (type === 'group' && Object.keys(value).length)
)
.map(({ id, value }) => [id, value]),
.map(({ id, value }) => [id, value])
)
}

View File

@@ -11,6 +11,7 @@
:label-width="labelWidth"
:style="{ '--label-width': labelWidth }"
v-bind="$attrs"
:server-errors="serverErrors"
v-on="$listeners"
>
<!-- slot 透传 -->
@@ -55,7 +56,7 @@
<el-button
v-for="button in moreButtons"
v-show="!button.hidden"
v-show="!iHidden(button)"
:key="button.title"
:loading="button.loading"
size="small"
@@ -121,6 +122,10 @@ export default {
type: Boolean,
default: true
},
serverErrors: {
type: Object,
default: () => ({})
},
fields: {
type: Array,
default: () => []
@@ -226,6 +231,9 @@ export default {
},
getFormValue() {
return this.$refs.form.getFormValue()
},
iHidden(item) {
return typeof item.hidden === 'function' ? item.hidden() : item.hidden
}
}
}
@@ -236,6 +244,10 @@ export default {
margin-right: 80px;
margin-bottom: 20px;
.el-form {
margin-right: 0;
}
::v-deep .el-input-group__prepend {
border-radius: 0;
}

View File

@@ -1,4 +1,5 @@
import i18n from '@/i18n/i18n'
import request from '@/utils/request'
export const Required = {
required: true, message: i18n.t('FieldRequiredError'), trigger: 'blur'
@@ -118,3 +119,69 @@ export default {
matchAlphanumericUnderscore,
MatchExcludeParenthesis
}
/**
* @description 表单唯一性校验
*
* @param {Object} options
* @param {string} 列表查询地址
* @param {string} 查询参数名
* @param {string} 字段中文名
* @param {string} 字段名
* @param {function(): (string|number)} 返回更新场景下的当前对象 id
*/
export function UniqueCheck(options = {}) {
const { url, param, label, fieldName, getIgnoreId } = options
function existsInResponse(res) {
if (Array.isArray(res)) return res.length > 0
if (res && typeof res === 'object') {
if (typeof res.count === 'number') return res.count > 0
if (Array.isArray(res.results)) return res.results.length > 0
}
return !!res
}
function extractIds(res) {
if (Array.isArray(res)) return res.map(i => i?.id).filter(Boolean)
if (res && Array.isArray(res.results)) return res.results.map(i => i?.id).filter(Boolean)
return []
}
return {
async validator(rule, value, callback) {
try {
let v = value
if (typeof v === 'string') v = v.trim()
if (v === '' || v === undefined || v === null) return callback()
if (!url || !param) return callback()
const res = await request.get(url, { params: { [param]: v } })
let duplicated = existsInResponse(res)
if (duplicated && typeof getIgnoreId === 'function') {
const curId = getIgnoreId()
if (curId) {
const ids = extractIds(res)
// 查询结果只包含自身,因此不被视为重复
if (ids.length >= 1 && ids.every(id => id === curId)) {
duplicated = false
}
}
}
if (duplicated) {
const _label = label || fieldName || ''
const msg = `${_label}${i18n.t('Existing')}`
callback(new Error(msg))
} else {
callback()
}
} catch (e) {
callback()
}
},
trigger: ['blur']
}
}

View File

@@ -14,6 +14,7 @@
<el-button
:type="item.el && item.el.type"
class="start-stop-btn"
:disabled="item.disabled"
size="mini"
@click="item.callback()"
>

View File

@@ -2,7 +2,7 @@
<div class="json-editor">
<JsonEditor
v-model="resultInfo"
:class="{resize: resize === 'vertical'}"
:class="{ resize: resize === 'vertical' }"
:mode="'code'"
:show-btns="false"
@json-change="onJsonChange"
@@ -24,7 +24,7 @@ export default {
},
resize: {
type: String,
validator: (value) => {
validator: value => {
return ['none', 'vertical'].indexOf(value) !== -1
},
default: 'vertical'
@@ -52,7 +52,7 @@ export default {
this.$emit('change', this.resultInfo)
}, 500)
},
onError: _.debounce(function(value) {
onError: _.debounce(function (value) {
this.$message.error(this.$tc('FormatError'))
}, 1500)
}
@@ -60,35 +60,38 @@ export default {
</script>
<style lang="scss" scoped>
@import "~@/styles/variables";
.json-editor {
.resize {
& ::v-deep .jsoneditor {
resize: vertical;
cursor: s-resize;
}
}
@import '~@/styles/variables';
.json-editor {
.resize {
& ::v-deep .jsoneditor {
border: 1px solid #e5e6e7;
}
& ::v-deep .jsoneditor-compact {
display: none;
}
& ::v-deep .jsoneditor-modes {
display: none;
}
& ::v-deep .jsoneditor-poweredBy {
display: none;
}
& ::v-deep .jsoneditor-menu {
background: var(--color-primary);
border-bottom: 1px solid var(--color-primary);
resize: vertical;
cursor: s-resize;
}
}
& ::v-deep .jsoneditor {
border: 1px solid #e5e6e7;
border-left: unset;
border-top: unset;
border-radius: 2px;
}
& ::v-deep .jsoneditor-compact {
display: none;
}
& ::v-deep .jsoneditor-modes {
display: none;
}
& ::v-deep .jsoneditor-poweredBy {
display: none;
}
& ::v-deep .jsoneditor-menu {
background: var(--color-primary);
border-bottom: 1px solid var(--color-primary);
}
}
</style>

View File

@@ -19,7 +19,7 @@ export default {
props: {
value: {
type: [Array, String, Number, Boolean, Object],
default: () => ([])
default: () => []
},
multiple: {
type: Boolean,
@@ -36,7 +36,7 @@ export default {
},
computed: {
attrsWithoutValue() {
const attrs = Object.assign({}, this.$attrs)
const attrs = Object.assign({ clearable: this.clearable }, this.$attrs)
delete attrs.value
return attrs
},
@@ -50,6 +50,13 @@ export default {
const value = this.objectsToValues(this.value)
return value
}
},
clearable() {
if (this.$attrs.clearable === undefined) {
return this.multiple
} else {
return this.$attrs.clearable
}
}
},
methods: {
@@ -71,8 +78,11 @@ export default {
value = value.map(v => {
// uuid v4
const uuid = /^[0-9A-F]{8}-[0-9A-F]{4}-[4][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i
return typeof v === 'object' ? v
: this.$attrs?.allowCreate && !uuid.test(v) ? { [this.customLabelKeyName]: v } : { pk: v }
return typeof v === 'object'
? v
: this.$attrs?.allowCreate && !uuid.test(v)
? { [this.customLabelKeyName]: v }
: { pk: v }
})
if (!this.multiple) {
value = value[0]
@@ -87,9 +97,13 @@ export default {
if (!Array.isArray(val)) {
val = [val]
}
val = val.map((v) => {
val = val.map(v => {
if (v && typeof v === 'object') {
return v.pk || v.id || (this.$attrs?.allowCreate ? (v?.[this.customLabelKeyName] + ':' + v?.value) : '')
return (
v.pk ||
v.id ||
(this.$attrs?.allowCreate ? v?.[this.customLabelKeyName] + ':' + v?.value : '')
)
} else {
return v
}
@@ -103,6 +117,4 @@ export default {
}
</script>
<style scoped>
</style>
<style scoped></style>

View File

@@ -12,7 +12,7 @@
width="800px"
v-on="$listeners"
>
<el-alert v-if="disabled && platformDetail" style="margin-bottom: 10px" type="success">
<el-alert v-if="disabled && platformDetail" style="margin-bottom: 10px" type="info">
{{ $t('InheritPlatformConfig') }}
<el-link :href="platformDetail" class="link-more" target="_blank">
{{ $t('View') }}
@@ -62,9 +62,7 @@ export default {
hasButtons: !this.disabled,
url: '/api/v1/assets/protocol-settings/?name=' + this.protocol.name,
fields: [
[vm.$t('Basic'), [
'primary', 'required', 'default', 'public'
]],
[vm.$t('Basic'), ['primary', 'required', 'default', 'public']],
[vm.$t('Advanced'), ['setting']]
],
fieldsMeta: {
@@ -72,23 +70,23 @@ export default {
fields: '__all__',
fieldsMeta: {
username_selector: {
hidden: (formValue) => formValue['autofill'] !== 'basic'
hidden: formValue => formValue['autofill'] !== 'basic'
},
password_selector: {
hidden: (formValue) => formValue['autofill'] !== 'basic'
hidden: formValue => formValue['autofill'] !== 'basic'
},
submit_selector: {
hidden: (formValue) => formValue['autofill'] !== 'basic'
hidden: formValue => formValue['autofill'] !== 'basic'
},
script: {
component: JsonEditor,
hidden: (formValue) => formValue['autofill'] !== 'script'
hidden: formValue => formValue['autofill'] !== 'script'
}
}
},
public: {
disabled: this.protocol.name === 'winrm',
hidden: (formValue) => {
hidden: formValue => {
if (this.protocol.name === 'winrm') {
formValue['public'] = false
}

View File

@@ -33,6 +33,9 @@
>
<i :class="[isCheckShowPassword ? 'fa-eye-slash' : 'fa-eye']" class="fa" />
</span>
<span v-if="filterTags.length > 0" class="clear-icon" @click="handleClearAll">
<i class="el-icon-circle-close" :title="$t('Clear')" />
</span>
</div>
</template>
@@ -140,6 +143,11 @@ export default {
},
handleShowPassword() {
this.isCheckShowPassword = !this.isCheckShowPassword
},
handleClearAll() {
this.filterTags = []
this.$emit('change', this.filterTags)
this.$emit('input', this.filterTags)
}
}
}
@@ -161,11 +169,12 @@ export default {
line-height: 30px;
&:hover {
border-color: #C0C4CC;
border-color: #c0c4cc;
}
& ::v-deep .el-tag {
margin-bottom: 1px;
margin-bottom: 2px;
margin-top: 2px;
font-family: sans-serif !important;
margin-left: 5px;
}
@@ -177,6 +186,7 @@ export default {
.search-input {
flex: 1;
min-width: 150px;
& ::v-deep .el-input__inner {
max-width: 100%;
@@ -204,4 +214,15 @@ export default {
color: #999999;
}
}
.clear-icon {
display: inherit;
padding-right: 6px;
cursor: pointer;
color: #c0c4cc;
&:hover {
color: #606164;
}
}
</style>

View File

@@ -68,7 +68,7 @@ export default {
return { label: item.name, value: item.id }
})
const url = vm.url || vm.ajax.url
const getPageData = async({ pageIndex, pageSize, keyword }) => {
const getPageData = async ({ pageIndex, pageSize, keyword }) => {
const limit = pageSize
const offset = (pageIndex - 1) * pageSize
const params = {

View File

@@ -0,0 +1,53 @@
<template>
<div>
<el-checkbox v-model="iValue">
{{ $t('ReadAgreeTo') }}
<a href="/core/auth/agreement/" target="_blank" style="color: #409eff">
{{ $t('TermsOfService') }}
</a>
{{ $t('and') }}
<a href="/core/auth/privacy/" target="_blank" style="color: #409eff">
{{ $t('PrivacyPolicy') }}
</a>
</el-checkbox>
</div>
</template>
<script>
export default {
props: {
value: {
type: Boolean,
default: () => false
}
},
data() {
return {
iValue: false
}
},
watch: {
iValue: {
handler(v) {
this.$emit('input', v)
}
}
},
created() {
this.iValue = this.value
},
computed: {
iValue: {
get() {
return this.value
},
set(v) {
this.$emit('update:value', v)
}
}
},
methods: {}
}
</script>
<style lang="scss" scoped></style>

View File

@@ -1,76 +1,71 @@
<template>
<div class="krry-main">
<el-row :gutter="10">
<el-col :md="11" :sm="24">
<krry-box
ref="noSelect"
:async="async"
:async-search-flag="asyncSearchFlag"
:data-show-list="notSelectDataList"
:filter-placeholder="filterPlaceholder[0] || $tc('Search')"
:filterable="filterable"
:highlight-color="highlightColor"
:is-highlight="isHighlight"
:is-last-page="isLastPage"
:operate-id="0"
:page-size="pageSize"
:page-texts="pageTexts"
:show-clear-btn="showClearBtn"
:title="boxTitle[0] || $tc('Selection')"
@check-district="noCheckSelect"
@search-word="searchWord"
@check-disable="checkDisable"
@get-data="getData"
@get-data-by-keyword="getDataByKeyword"
@clear-input="clearQueryInp('left')"
<krry-box
ref="noSelect"
:async="async"
:async-search-flag="asyncSearchFlag"
:data-show-list="notSelectDataList"
:filter-placeholder="filterPlaceholder[0] || $tc('Search')"
:filterable="filterable"
:highlight-color="highlightColor"
:is-highlight="isHighlight"
:is-last-page="isLastPage"
:operate-id="0"
:page-size="pageSize"
:page-texts="pageTexts"
:show-clear-btn="showClearBtn"
:title="boxTitle[0] || $tc('Selection')"
@check-district="noCheckSelect"
@search-word="searchWord"
@check-disable="checkDisable"
@get-data="getData"
@get-data-by-keyword="getDataByKeyword"
@clear-input="clearQueryInp('left')"
/>
<div class="opera">
<svg-icon v-if="transferOnCheck" class="arrow" icon-class="arrow" />
<template v-else>
<el-button
:disabled="disablePre"
class="el-transfer__button"
icon="el-icon-arrow-left"
size="mini"
@click="deleteData"
/>
</el-col>
<el-col :md="2" :sm="24" class="buttons">
<div class="opera">
<svg-icon v-if="transferOnCheck" class="arrow" icon-class="arrow" />
<template v-else>
<el-button
:disabled="disablePre"
class="el-transfer__button"
icon="el-icon-arrow-left"
size="mini"
@click="deleteData"
/>
<el-button
:disabled="disableNex"
class="el-transfer__button"
icon="el-icon-arrow-right"
size="mini"
type="primary"
@click="addData"
/>
</template>
</div>
</el-col>
<el-col :md="11" :sm="24">
<krry-box
ref="hasSelect"
:data-show-list="checkedData"
:filter-placeholder="filterPlaceholder[1] || $tc('Search')"
:filterable="filterable"
:highlight-color="highlightColor"
:is-highlight="isHighlight"
:operate-id="1"
:page-size="pageSize"
:page-texts="pageTexts"
:show-clear-btn="showClearBtn"
:title="boxTitle[1] || $tc('Selected')"
@check-district="hasCheckSelect"
@search-word="searchWord"
@check-disable="checkDisable"
@clear-input="clearQueryInp('right')"
<el-button
:disabled="disableNex"
class="el-transfer__button"
icon="el-icon-arrow-right"
size="mini"
type="primary"
@click="addData"
/>
</el-col>
</el-row>
</template>
</div>
<krry-box
ref="hasSelect"
:data-show-list="checkedData"
:filter-placeholder="filterPlaceholder[1] || $tc('Search')"
:filterable="filterable"
:highlight-color="highlightColor"
:is-highlight="isHighlight"
:operate-id="1"
:page-size="pageSize"
:page-texts="pageTexts"
:show-clear-btn="showClearBtn"
:title="boxTitle[1] || $tc('Selected')"
@check-district="hasCheckSelect"
@search-word="searchWord"
@check-disable="checkDisable"
@clear-input="clearQueryInp('right')"
/>
</div>
</template>
<script>
/* eslint-disable */
import krryBox from './models/box'
export default {
@@ -212,20 +207,14 @@ export default {
// this.checkedData 为空 且 从来没有将已选区置为空,则从 selectedData 获取
if ((!this.checkedData.length && !this.manualEmpty) || selectedChange) {
this.checkedData = JSON.parse(JSON.stringify(this.selectedData))
const keywords = this.$refs.hasSelect
? this.$refs.hasSelect.searchWord
: ''
const keywords = this.$refs.hasSelect ? this.$refs.hasSelect.searchWord : ''
keywords && this.searchWord(keywords, 1)
}
if (!this.async) {
this.selectListCheck = JSON.parse(JSON.stringify(this.checkedData))
const checkDataId = this.selectListCheck.map(ele => ele.id)
this.notSelectDataList = this.originList.filter(
ele => !checkDataId.includes(ele.id)
)
this.dataListNoCheck = JSON.parse(
JSON.stringify(this.notSelectDataList)
)
this.notSelectDataList = this.originList.filter(ele => !checkDataId.includes(ele.id))
this.dataListNoCheck = JSON.parse(JSON.stringify(this.notSelectDataList))
} else {
if (selectedChange) {
this.selectListCheck = JSON.parse(JSON.stringify(this.checkedData))
@@ -236,9 +225,7 @@ export default {
!checkDataId.includes(ele.id) &&
(ele.label.includes(this.noSelectKeyword) || this.asyncSearchFlag)
)
this.dataListNoCheck = this.originList.filter(
ele => !checkDataId.includes(ele.id)
)
this.dataListNoCheck = this.originList.filter(ele => !checkDataId.includes(ele.id))
}
},
searchWord(keyword, titleId) {
@@ -247,15 +234,11 @@ export default {
if (titleId === 0) {
this.noSelectKeyword = keyword
if (!this.asyncSearchFlag) {
this.notSelectDataList = this.dataListNoCheck.filter(val =>
val.label.includes(keyword)
)
this.notSelectDataList = this.dataListNoCheck.filter(val => val.label.includes(keyword))
}
} else {
this.haSelectKeyword = keyword
this.checkedData = this.selectListCheck.filter(val =>
val.label.includes(keyword)
)
this.checkedData = this.selectListCheck.filter(val => val.label.includes(keyword))
}
const refsName = titleId === 0 ? 'noSelect' : 'hasSelect'
// 延迟执行
@@ -294,29 +277,21 @@ export default {
!noCheckDataId.includes(ele.id) &&
(ele.label.includes(this.noSelectKeyword) || this.asyncSearchFlag)
)
this.dataListNoCheck = this.dataListNoCheck.filter(
ele => !noCheckDataId.includes(ele.id)
)
this.dataListNoCheck = this.dataListNoCheck.filter(ele => !noCheckDataId.includes(ele.id))
// 已选区数据增加
if (!this.async && this.sort) {
// 排序,从固定不变的所有数据中过滤,顺序就不会乱。但若数据量大就会比较卡
// 异步分页不支持排序
const dataListNoCheckId = this.dataListNoCheck.map(ele => ele.id)
this.checkedData = this.originList.filter(
ele =>
!dataListNoCheckId.includes(ele.id) &&
ele.label.includes(this.haSelectKeyword)
)
this.selectListCheck = this.originList.filter(
ele => !dataListNoCheckId.includes(ele.id)
ele => !dataListNoCheckId.includes(ele.id) && ele.label.includes(this.haSelectKeyword)
)
this.selectListCheck = this.originList.filter(ele => !dataListNoCheckId.includes(ele.id))
} else {
// 这种效率更高的方法,但不能排序
this.checkedData.push(...this.noCheckData)
this.selectListCheck.push(...this.noCheckData)
this.checkedData = this.checkedData.filter(ele =>
ele.label.includes(this.haSelectKeyword)
)
this.checkedData = this.checkedData.filter(ele => ele.label.includes(this.haSelectKeyword))
}
},
// 从已选中删除
@@ -324,13 +299,9 @@ export default {
// 已选区数据过滤
const hasCheckDataId = this.hasCheckData.map(ele => ele.id)
this.checkedData = this.checkedData.filter(
ele =>
!hasCheckDataId.includes(ele.id) &&
ele.label.includes(this.haSelectKeyword)
)
this.selectListCheck = this.selectListCheck.filter(
ele => !hasCheckDataId.includes(ele.id)
ele => !hasCheckDataId.includes(ele.id) && ele.label.includes(this.haSelectKeyword)
)
this.selectListCheck = this.selectListCheck.filter(ele => !hasCheckDataId.includes(ele.id))
this.manualEmpty = !this.checkedData.length
@@ -343,9 +314,7 @@ export default {
!selectListCheckId.includes(ele.id) &&
(ele.label.includes(this.noSelectKeyword) || this.asyncSearchFlag)
)
this.dataListNoCheck = this.originList.filter(
ele => !selectListCheckId.includes(ele.id)
)
this.dataListNoCheck = this.originList.filter(ele => !selectListCheckId.includes(ele.id))
},
// 提供获取已选数据的钩子
getSelectedData() {
@@ -370,11 +339,7 @@ export default {
this.$nextTick(() => {
this.$refs.noSelect.asyncSearch = true
})
const resData = await this.getSearchData(
keyword,
pageIndex,
this.pageSize
)
const resData = await this.getSearchData(keyword, pageIndex, this.pageSize)
if (Array.isArray(resData) && resData.length) {
this.asyncDataList = resData
this.notSelectDataList = resData
@@ -416,45 +381,34 @@ export default {
<style lang="scss" scoped>
.krry-main {
min-width: 600px;
}
.inner-center {
margin: 0 5px;
}
.buttons {
vertical-align: middle;
}
.opera {
position: relative;
display: flex;
justify-content: center;
align-items: center;
height: 415px;
justify-content: space-around;
min-width: 600px;
.arrow {
width: 1.25em;
height: 1.25em;
color: #888888;
}
.opera {
position: relative;
display: flex;
justify-content: center;
align-items: center;
height: 415px;
@media screen and (max-width: 992px) {
margin: 8px 8px;
text-align: start
}
.arrow {
width: 1.25em;
height: 1.25em;
color: #888888;
}
.el-button.is-circle {
border-radius: 50%;
padding: 12px;
display: block;
margin: 25px auto;
}
.el-button.is-circle {
border-radius: 50%;
padding: 12px;
display: block;
margin: 25px auto;
}
.el-transfer__button {
padding: 5px;
.el-transfer__button {
padding: 5px;
}
}
}
</style>

View File

@@ -5,6 +5,11 @@
<slot name="no-data" />
</template>
<template v-else>
<!--
过滤 selection 相关事件的透传避免父组件收到 el-table 原生的当前页 selection
导致跨页选择persistSelection被覆盖只剩当页数据
选择事件统一走 selectStrategy在内部维护全量 selected 并向外 emit
-->
<el-table
ref="table"
v-loading="tableLoading"
@@ -12,7 +17,7 @@
:row-class-name="rowClassName"
v-bind="tableAttrs"
@select="selectStrategy.onSelect"
v-on="$listeners"
v-on="forwardListeners"
@selection-change="selectStrategy.onSelectionChange"
@select-all="handleSelectAll($event, canSelect)"
@sort-change="onSortChange"
@@ -23,27 +28,18 @@
<template v-if="hasSelect">
<el-data-table-column
key="selection-key"
v-bind="{align: columnsAlign, ...columns[0]}"
v-bind="{ align: columnsAlign, ...columns[0] }"
/>
<el-data-table-column
key="tree-ctrl"
v-bind="{align: columnsAlign, ...columns[1]}"
>
<el-data-table-column key="tree-ctrl" v-bind="{ align: columnsAlign, ...columns[1] }">
<template slot-scope="scope">
<span
v-for="space in scope.row._level"
:key="space"
class="ms-tree-space"
/>
<span v-for="space in scope.row._level" :key="space" class="ms-tree-space" />
<span
v-if="iconShow(scope.$index, scope.row)"
class="tree-ctrl"
@click="toggleExpanded(scope.$index)"
>
<i
:class="`el-icon-${scope.row._expanded ? 'minus' : 'plus'}`"
/>
<i :class="`el-icon-${scope.row._expanded ? 'minus' : 'plus'}`" />
</span>
{{ scope.row[columns[1].prop] }}
</template>
@@ -52,23 +48,16 @@
<el-data-table-column
v-for="col in columns.filter((c, i) => i !== 0 && i !== 1)"
:key="col.prop"
v-bind="{align: columnsAlign, ...col}"
v-bind="{ align: columnsAlign, ...col }"
/>
</template>
<!--无选择-->
<template v-else>
<!--展开这列, 丢失 el-data-table-column属性-->
<el-data-table-column
key="tree-ctrl"
v-bind="{align: columnsAlign, ...columns[0]}"
>
<el-data-table-column key="tree-ctrl" v-bind="{ align: columnsAlign, ...columns[0] }">
<template slot-scope="scope">
<span
v-for="space in scope.row._level"
:key="space"
class="ms-tree-space"
/>
<span v-for="space in scope.row._level" :key="space" class="ms-tree-space" />
<span
v-if="iconShow(scope.$index, scope.row)"
@@ -84,14 +73,19 @@
<el-data-table-column
v-for="col in columns.filter((c, i) => i !== 0)"
:key="col.prop"
v-bind="{align: columnsAlign, ...col}"
v-bind="{ align: columnsAlign, ...col }"
/>
</template>
</template>
<!--非树-->
<template v-else>
<el-data-table-column v-if="hasSelection" :align="selectionAlign" :selectable="canSelect" type="selection" />
<el-data-table-column
v-if="hasSelection"
:align="selectionAlign"
:selectable="canSelect"
type="selection"
/>
<el-data-table-column
v-for="col in columns"
:key="col.prop"
@@ -100,14 +94,14 @@
:filters="col.filters || null"
:formatter="typeof col.formatter === 'function' ? col.formatter : null"
:title="col.label"
v-bind="{align: columnsAlign, ...col}"
v-bind="{ align: columnsAlign, ...col }"
>
<template #header>
<span :title="col.label">{{ col.label }}</span>
</template>
<template
v-if="col.formatter && typeof col.formatter !== 'function'"
v-slot:default="{row, column, $index}"
v-slot:default="{ row, column, $index }"
>
<div
:is="col.formatter"
@@ -161,9 +155,9 @@
</template>
<script>
import _get from 'lodash.get'
import _values from 'lodash.values'
import _isEmpty from 'lodash.isempty'
import _get from 'lodash/get'
import _values from 'lodash/values'
import _isEmpty from 'lodash/isEmpty'
import SelfLoadingButton from './components/self-loading-button.vue'
import TheDialog, { dialogModes } from './components/the-dialog.vue'
import ElDataTableColumn from './components/el-data-table-column'
@@ -275,8 +269,7 @@ export default {
*/
beforeSearch: {
type: Function,
default() {
}
default() {}
},
/**
* 单选, 适用场景: 不可以批量删除
@@ -441,8 +434,7 @@ export default {
*/
onEdit: {
type: Function,
default(row) {
}
default(row) {}
},
/**
* 点击删除按钮时的方法, 当默认删除方法不满足需求时使用, 需要返回promise
@@ -451,9 +443,7 @@ export default {
onDelete: {
type: Function,
default(data) {
const ids = Array.isArray(data)
? data.map(v => v[this.id]).join(',')
: data[this.id]
const ids = Array.isArray(data) ? data.map(v => v[this.id]).join(',') : data[this.id]
return this.$axios.delete(this.url + '/' + ids + '/', this.axiosConfig)
}
},
@@ -707,8 +697,8 @@ export default {
}
},
/*
* 设置默认对齐方式
*/
* 设置默认对齐方式
*/
defaultAlign: {
type: String,
default: 'center'
@@ -723,8 +713,7 @@ export default {
},
extraPaginationAttrs: {
type: Object,
default: () => {
}
default: () => {}
},
hasSelection: {
type: Boolean,
@@ -810,6 +799,16 @@ export default {
selectStrategy() {
return getSelectStrategy(this)
},
// 过滤会与内部选择策略冲突的事件,避免父组件只拿到当前页 selection
forwardListeners() {
const listeners = { ...this.$listeners }
delete listeners['selection-change']
delete listeners['select']
delete listeners['select-all']
// 外层如需监听 selection 变化,请监听本组件透出的 selection-change
// 该事件来自选择策略,已汇总跨页后的全量 selected
return listeners
},
searchLocatedSlotKeys() {
return getLocatedSlotKeys(this.$slots, 'search:')
},
@@ -897,9 +896,7 @@ export default {
}
Object.assign(query, this._extraQuery)
Object.assign(query, this.innerQuery)
query[this.pageSizeKey] = this.hasPagination
? this.size
: this.noPaginationSize
query[this.pageSizeKey] = this.hasPagination ? this.size : this.noPaginationSize
// 根据偏移值计算接口正确的页数
const pageOffset = this.firstPage - defaultFirstPage
@@ -981,9 +978,7 @@ export default {
formValue = this.$refs.searchForm.getFormValue()
Object.assign(query, formValue)
}
const queryStr =
(url.indexOf('?') > -1 ? '&' : '?') +
queryUtil.stringify(query, '=', '&')
const queryStr = (url.indexOf('?') > -1 ? '&' : '?') + queryUtil.stringify(query, '=', '&')
// 请求开始
this.tableLoading = loading
@@ -1003,10 +998,7 @@ export default {
// 不分页
if (!this.hasPagination) {
data =
_get(resp, this.dataPath) ||
_get(resp, noPaginationDataPath) ||
[]
data = _get(resp, this.dataPath) || _get(resp, noPaginationDataPath) || []
this.total = data.length
} else {
data = _get(resp, this.dataPath) || []
@@ -1189,7 +1181,7 @@ export default {
this.$confirm(this.deleteMessage(data), this.$t('Info'), {
type: 'warning',
confirmButtonClass: 'el-button--danger',
beforeClose: async(action, instance, done) => {
beforeClose: async (action, instance, done) => {
if (action !== 'confirm') return done()
instance.confirmButtonLoading = true
@@ -1225,11 +1217,7 @@ export default {
}
const remain = this.data.length - deleteCount
const lastPage = Math.ceil(this.total / this.size)
if (
remain === 0 &&
this.page === lastPage &&
this.page > defaultFirstPage
) {
if (remain === 0 && this.page === lastPage && this.page > defaultFirstPage) {
this.page--
}
},
@@ -1257,20 +1245,14 @@ export default {
tmp.push(record)
if (record[this.treeChildKey] && record[this.treeChildKey].length > 0) {
const children = this.tree2Array(
record[this.treeChildKey],
expandAll,
record,
_level
)
const children = this.tree2Array(record[this.treeChildKey], expandAll, record, _level)
tmp = tmp.concat(children)
}
})
return tmp
},
rowClassName(...args) {
let rcn =
this.tableAttrs.rowClassName || this.tableAttrs['row-class-name'] || ''
let rcn = this.tableAttrs.rowClassName || this.tableAttrs['row-class-name'] || ''
if (typeof rcn === 'function') rcn = rcn(...args)
if (this.isTree) rcn += ' ' + this.showRow(...args)
return rcn

View File

@@ -1,14 +1,9 @@
/**
* 两种多选策略Normal 和 PersistSelection
*/
/**
* 多选策略接口
*/
class StrategyAbstract {
constructor(elDataTable) {
this.elDataTable = elDataTable
// 绑定this后可直接在template中使用
this.onSelectionChange = this.onSelectionChange.bind(this)
this.onSelect = this.onSelect.bind(this)
this.onSelectAll = this.onSelectAll.bind(this)
@@ -18,39 +13,22 @@ class StrategyAbstract {
return this.elDataTable.$refs.table
}
onSelectionChange() {
}
onSelect() {
}
onSelectAll() {
}
toggleRowSelection() {
}
clearSelection() {
}
updateElTableSelection() {
}
onSelectionChange() {}
onSelect() {}
onSelectAll() {}
toggleRowSelection() {}
clearSelection() {}
updateElTableSelection() {}
}
/**
* 普通策略。由el-table维护selected
* 普通策略。由 el-table 自己维护 selection
*/
class StrategyNormal extends StrategyAbstract {
/**
* normal模式下只需要监听selection-change事件
*/
onSelectionChange(val) {
this.elDataTable.selected = val
}
/**
* toggleRowSelection和clearSelection的表现与el-table一致
*/
toggleRowSelection(...args) {
return this.elTable.toggleRowSelection(...args)
}
@@ -61,44 +39,28 @@ class StrategyNormal extends StrategyAbstract {
}
/**
* 跨页保存多选策略。手动维护selected数组
* 跨页保存多选策略
*/
class StrategyPersistSelection extends StrategyAbstract {
/**
* el-table的selection-change事件不适用于开启跨页保存的情况。
* 比如当开启persistSelection时发生以下两个场景
* 1. 用户点击翻页
* 2. 用户点击行首的切换全选项按钮,清空当前页多选项数据
* 其中场景1应该保持selected不变而场景2只应该从selected移除当前页所有行保留其他页面的多选状态。
* 但el-table的selection-change事件在两个场景中无差别发生所以这里不处理这个事件
*/
/**
* 用户切换某一行的多选
*/
onSelect(selection, row) {
const isChosen = selection.indexOf(row) > -1
this.toggleRowSelection(row, isChosen)
// el-table 原生 selection-change 仅包含当前页。为保证跨页勾选有效,
// 在内部策略维护完 selected 后,向外部同步“全量已选”。
this.elDataTable.$emit('selection-change', this.elDataTable.selected)
}
/**
* 用户切换当前页的多选
*/
onSelectAll(selection, selectable = () => true) {
const { id, selected, data } = this.elDataTable
const selectableRows = data.filter(selectable)
// const isSelected = !!selection.length
// 创建已选择项的 id 集合,用于快速查找
const selectedIds = new Set(selected.map(r => r[id]))
const currentPageIds = new Set(selectableRows.map(row => row[id]))
// 前页面的选中状态
const currentPageSelectedCount = selectableRows.filter(row =>
selectedIds.has(row[id])
).length
// 判断是全选还是取消全选
const shouldSelectAll = currentPageSelectedCount < selectableRows.length
this.elTable?.clearSelection()
@@ -106,15 +68,11 @@ class StrategyPersistSelection extends StrategyAbstract {
if (shouldSelectAll) {
selectableRows.forEach(row => {
if (!selectedIds.has(row[id])) selected.push(row)
this.elTable.toggleRowSelection(row, true)
// ! 这里需要触发事件,否则在 el-table 中无法触发 selection-change 事件
this.elDataTable.$emit('toggle-row-selection', true, row)
})
} else {
const newSelected = []
selected.forEach(row => {
if (!currentPageIds.has(row[id])) {
newSelected.push(row)
@@ -122,17 +80,12 @@ class StrategyPersistSelection extends StrategyAbstract {
this.elDataTable.$emit('toggle-row-selection', false, row)
}
})
this.elDataTable.selected = newSelected
}
this.elDataTable.$emit('selection-change', this.elDataTable.selected)
}
/**
* toggleRowSelection和clearSelection管理elDataTable的selected数组
* 记得最后要将状态同步到el-table中
*/
toggleRowSelection(row, isSelected) {
const { id, selected } = this.elDataTable
const foundIndex = selected.findIndex(r => r[id] === row[id])
@@ -149,26 +102,24 @@ class StrategyPersistSelection extends StrategyAbstract {
this.elDataTable.$emit('toggle-row-selection', isSelected, row)
this.updateElTableSelection()
// 切换后同步全量 selection跨页
this.elDataTable.$emit('selection-change', this.elDataTable.selected)
}
clearSelection() {
this.elDataTable.selected = []
this.updateElTableSelection()
// 清空后也同步给外部,保持外层状态一致
this.elDataTable.$emit('selection-change', this.elDataTable.selected)
}
/**
* 将selected状态同步到el-table中
*/
updateElTableSelection() {
const { data, id, selected } = this.elDataTable
const selectedIds = new Set(selected.map(r => r[id]))
this.elTable?.clearSelection()
data.forEach(row => {
const shouldBeSelected = selectedIds.has(row[id])
if (!this.elTable) return
if (shouldBeSelected) {
this.elTable.toggleRowSelection(row, true)
}

View File

@@ -167,7 +167,6 @@ export default {
}
}
</script>
<style lang="scss" scoped>
.el-data-table {
::v-deep .el-pagination.is-background .el-pager li {

View File

@@ -107,8 +107,8 @@ export default {
const formatterArgs = value?.formatterArgs
// console.log('>>> name: ', key)
// console.log('>>> formatter: ', formatter)
const detailFormaters = ['AmountFormatter', 'DetailFormatter']
if (formatter && detailFormaters.includes(formatter.name) && formatterArgs.drawer !== false) {
const detailFormatters = ['AmountFormatter', 'DetailFormatter']
if (formatter && detailFormatters.includes(formatter.name) && formatterArgs.drawer !== false) {
formatterArgs.onClick = this.onDetail
}
}
@@ -223,7 +223,6 @@ export default {
}
title = actionLabel + this.$t('WordSep') + toLowerCaseExcludeAbbr(title)
return title
},
getDefaultDrawer(action) {
@@ -295,7 +294,6 @@ export default {
// 3. 设置组件
this.drawerComponent = this.getDrawerComponent(action, payload)
this.$log.debug('>>> drawerComponent: ', this.drawerComponent)
this.drawerTitle = this.getActionDrawerTitle({ action, row, col, cellValue, payload })
// 4. 如果没有组件,尝试获取默认组件
if (!this.drawerComponent) {
@@ -312,6 +310,7 @@ export default {
const actionMeta = await this.$store.getters['common/drawerActionMeta']
this.title = this.getDrawerTitle({ action, ...actionMeta })
}
this.drawerTitle = this.getActionDrawerTitle({ action, row, col, cellValue, payload })
// 7. 等待下一个 tick确保组件已设置
await this.$nextTick()

View File

@@ -4,15 +4,11 @@
<div class="panel-title">
<el-avatar :src="imageUrl" shape="square" />
<div class="title-display">
<span class="name">{{ object.name }}</span>
<p class="name" :title="object.name">{{ object.name }}</p>
<span class="comment">{{ object.provider.label }}</span>
</div>
</div>
<div
v-if="iActions.length !== 0"
class="panel-actions"
@click="handleClick($event)"
>
<div v-if="iActions.length !== 0" class="panel-actions" @click="handleClick($event)">
<el-dropdown>
<el-button size="mini">
<i class="el-icon-more el-icon--right" />
@@ -64,21 +60,19 @@ export default {
},
getImage: {
type: Function,
default: (obj) => ''
default: obj => ''
},
getInfos: {
type: Function,
default: (obj) => []
default: obj => []
},
handleUpdate: {
type: Function,
default: () => {
}
default: () => {}
},
onView: {
type: Function,
default: () => {
}
default: () => {}
}
},
data() {
@@ -152,13 +146,13 @@ export default {
</script>
<style lang="scss" scoped>
div.info-panel {
display: flex;
flex-direction: column;
padding: 10px;
gap: 10px;
gap: unset;
cursor: pointer;
height: initial !important;
.panel-header {
padding: 10px 20px;
@@ -175,12 +169,23 @@ div.info-panel {
.title-display {
display: flex;
flex-basis: 225px;
flex-direction: column;
text-align: left;
justify-content: center;
align-items: flex-start;
max-width: 225px;
min-width: 0;
overflow-x: hidden;
.name {
font-size: 1.1em;
color: #555555;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
width: 100%;
margin: unset;
text-align: start;
}
.comment {
@@ -193,6 +198,7 @@ div.info-panel {
::v-deep {
.el-avatar {
background: #fff;
flex-shrink: 0;
}
}
}

View File

@@ -22,8 +22,8 @@
<div style="line-height: 1.5">
<span class="el-upload__tip">
{{ downloadTemplateTitle }}
<el-link type="success" @click="downloadTemplateFile('csv')"> CSV </el-link>
<el-link type="success" @click="downloadTemplateFile('xlsx')"> XLSX </el-link>
<el-link type="primary" @click="downloadTemplateFile('csv')"> CSV </el-link>
<el-link type="primary" @click="downloadTemplateFile('xlsx')"> XLSX </el-link>
</span>
</div>
</el-form-item>
@@ -58,6 +58,7 @@
:import-option="importOption"
:json-data="jsonData"
:url="url"
v-bind="$attrs"
@cancel="cancelUpload"
@finish="closeDialog"
/>
@@ -247,46 +248,46 @@ export default {
</script>
<style lang='scss' scoped>
@import "~@/styles/variables";
@import "~@/styles/variables";
.error-msg {
color: $--color-danger;
.error-msg {
color: $--color-danger;
}
.error-msg.error-results {
background-color: #f3f3f4;
max-height: 200px;
overflow: auto
}
.file-uploader ::v-deep .el-upload {
width: 100%;
//padding-right: 150px;
}
.file-uploader ::v-deep .el-upload-dragger {
width: 100%;
}
.importTableZone {
padding: 0 20px;
.importTable {
overflow: auto;
}
.error-msg.error-results {
background-color: #f3f3f4;
max-height: 200px;
overflow: auto
.tableFilter {
padding-bottom: 10px;
}
}
.file-uploader ::v-deep .el-upload {
width: 100%;
//padding-right: 150px;
}
.importTable ::v-deep .el-dialog__body {
padding-bottom: 20px;
}
.file-uploader ::v-deep .el-upload-dragger {
width: 100%;
}
.importTableZone {
padding: 0 20px;
.importTable {
overflow: auto;
}
.tableFilter {
padding-bottom: 10px;
}
}
.importTable ::v-deep .el-dialog__body {
padding-bottom: 20px;
}
.export-item {
margin-left: 80px;
}
.export-item {
margin-left: 80px;
}
.export-item:first-child {
margin-left: 0;

View File

@@ -97,6 +97,10 @@ export default {
origin: {
type: String,
default: ''
},
encryptFields: {
type: Array,
default: () => []
}
},
data() {
@@ -273,11 +277,15 @@ export default {
}
return columns
},
getEncryptFields() {
const fromProp = Array.isArray(this.encryptFields) && this.encryptFields.length ? this.encryptFields : null
return fromProp || ['password', 'secret', 'private_key']
},
generateTableData(tableTitles, tableData) {
const totalData = []
tableData.forEach(item => {
this.$set(item, '@status', 'pending')
const encryptFields = ['password', 'secret', 'private_key']
const encryptFields = this.getEncryptFields()
for (const field of encryptFields) {
if (item[field]) {
item[field] = encryptPassword(item[field])

View File

@@ -1,11 +1,6 @@
<template>
<div class="label-search">
<el-button
v-if="!showLabelSearch"
class="label-button"
size="small"
@click="showSearchSelect"
>
<el-button v-if="!showLabelSearch" class="label-button" size="small" @click="showSearchSelect">
<svg-icon icon-class="tag" />
</el-button>
<el-cascader
@@ -100,7 +95,7 @@ export default {
setTimeout(() => {
this.$refs.labelCascader.updateStyle()
input.style.height = '30px'
},)
})
return
} else {
input.style.height = '30px'
@@ -147,41 +142,44 @@ export default {
}, 200)
},
listenViewPort() {
window.addEventListener('resize', debounce((e) => {
const viewPort = e?.target?.innerWidth
this.showLabelSearch = viewPort < 992
}, 100), false)
window.addEventListener(
'resize',
debounce(e => {
const viewPort = e?.target?.innerWidth
this.showLabelSearch = viewPort < 992
}, 100),
false
)
}
}
}
</script>
<style lang='scss' scoped>
<style lang="scss" scoped>
.label-search {
margin-right: 10px;
border: 1px solid var(--color-border);
overflow: hidden;
::v-deep .el-button.label-button {
height: 28px;
border: none;
padding: 8px;
}
.label-cascader {
width: 300px;
height: 28px;
line-height: 28px;
line-height: unset !important;
::v-deep .el-input {
.el-input__inner {
height: 28px !important;
line-height: 28px;
font-size: 13px;
border: none;
}
.el-input__suffix {
color: var(--color-icon-primary) !important;;
color: var(--color-icon-primary) !important;
}
}

View File

@@ -111,7 +111,7 @@ export default {
{
name: 'actionFilter',
icon: 'filter',
tip: this.$t('Filter'),
tip: this.$t('QuickFilter'),
has: this.hasQuickFilter,
callback: this.handleFilterClick.bind(this)
},

View File

@@ -86,13 +86,11 @@ export default {
},
datePick: {
type: Function,
default: (val) => {
}
default: val => {}
},
searchTable: {
type: Function,
default: (val) => {
}
default: val => {}
},
selectedRows: {
type: Array,
@@ -153,7 +151,7 @@ export default {
}
</script>
<style lang='scss' scoped>
<style lang="scss" scoped>
$innerHeight: 28px;
$headerHeight: 30px;
@@ -180,6 +178,7 @@ $headerHeight: 30px;
.right-side-item.action-search {
border: 1px solid var(--color-border);
overflow: hidden;
border-radius: 4px;
}
}
@@ -191,6 +190,8 @@ $headerHeight: 30px;
.search.right {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
padding-right: 10px;
}
}
@@ -239,5 +240,4 @@ $headerHeight: 30px;
display: block;
padding: 5px 20px;
}
</style>

View File

@@ -9,7 +9,7 @@
/>
<TableAction
v-if="hasActions"
:class="{'filter-expand': filterExpand}"
:class="{ 'filter-expand': filterExpand }"
:date-pick="handleDateChange"
:has-quick-filter="iHasQuickFilter"
:quick-filter-expand.sync="filterExpand"
@@ -85,10 +85,13 @@ export default {
date_from: getDaysAgo(7).toISOString(),
date_to: this.$moment(getDayEnd()).add(1, 'day').toISOString()
}
this.headerActions.datePicker = Object.assign({
dateStart: extraQuery.date_from,
dateEnd: extraQuery.date_to
}, this.headerActions.datePicker)
this.headerActions.datePicker = Object.assign(
{
dateStart: extraQuery.date_from,
dateEnd: extraQuery.date_to
},
this.headerActions.datePicker
)
}
if (this.$route.query.order) {
extraQuery['order'] = this.$route.query.order
@@ -169,7 +172,7 @@ export default {
extraQuery: this.extraQuery
})
const checkRoot = !(this.$route.meta?.disableOrgsChange === true)
const checkPermAndRoot = (action) => {
const checkPermAndRoot = action => {
if (!this.hasActionPerm(action)) {
return this.$t('NoPermission')
}
@@ -387,9 +390,4 @@ export default {
}
}
}
//修改颜色
.el-button--text {
color: #409EFF;
}
</style>

View File

@@ -23,7 +23,7 @@ const defaultPerformDelete = function({ row, col }) {
const defaultUpdateCallback = function({ row, col }) {
const id = row.id
let route = { params: { id: id }}
let route = { params: { id: id } }
const updateRoute = this.colActions.updateRoute
if (typeof updateRoute === 'object') {
@@ -39,7 +39,7 @@ const defaultUpdateCallback = function({ row, col }) {
const defaultViewCallback = function({ row, col }) {
const id = row.id
let route = { params: { id: id }}
let route = { params: { id: id } }
const viewRoute = this.colActions.viewRoute
if (typeof updateRoute === 'object') {
@@ -55,7 +55,7 @@ const defaultViewCallback = function({ row, col }) {
const defaultCloneCallback = function({ row, col }) {
const id = row.id
let route = { query: { clone_from: id }}
let route = { query: { clone_from: id } }
const cloneRoute = this.colActions.cloneRoute
if (typeof cloneRoute === 'object') {
@@ -82,7 +82,7 @@ const defaultDeleteCallback = function({ row, col, cellValue, reload }) {
type: 'warning',
confirmButtonClass: 'el-button--danger',
showCancelButton: true,
beforeClose: async(action, instance, done) => {
beforeClose: async (action, instance, done) => {
if (action !== 'confirm') return done()
instance.confirmButtonLoading = true
try {

View File

@@ -21,7 +21,7 @@ const formatterArgsDefault = {
false: 'fa-times-circle'
},
classChoices: {
true: 'text-primary',
true: 'text-success',
false: 'text-danger'
},
getKey({ row, cellValue }) {
@@ -100,7 +100,3 @@ export default {
methods: {}
}
</script>
<style scoped>
</style>

View File

@@ -1,6 +1,6 @@
<template>
<div>
<el-link :type="col.type || 'success'" class="detail" @click="dialogVisible=true">
<el-link :type="col.type || 'primary'" class="detail" @click="dialogVisible=true">
{{ iTitle }}
</el-link>
<Dialog

View File

@@ -38,6 +38,7 @@
<script>
import { copy, downloadText } from '@/utils/common/index'
import BaseFormatter from '@/components/Table/TableFormatters/base.vue'
import { mapGetters } from 'vuex'
export default {
name: 'SecretViewerFormatter',
@@ -69,6 +70,9 @@ export default {
}
},
computed: {
...mapGetters({
publicSettings: 'publicSettings'
}),
hasShow: function() {
return this.formatterArgs.hasShow
},
@@ -140,6 +144,10 @@ export default {
},
methods: {
async getAccountSecret() {
if (!this.publicSettings.SECURITY_ACCOUNT_SECRET_READ) {
this.$message.warning(this.$tc('AccountSecretReadDisabled'))
return
}
if (this.formatterArgs.secretFrom === 'cellValue' || this.getIt) {
return
}
@@ -178,48 +186,48 @@ export default {
}
</script>
<style lang="scss" scoped>
.content {
display: inline-block;
width: 100%;
.content {
display: inline-block;
width: 100%;
overflow: hidden;
//white-space: nowrap;
text-overflow: ellipsis;
font-size: 13px;
.text {
flex: 1;
display: inline;
margin: 0;
padding: 0;
overflow: hidden;
//white-space: nowrap;
white-space: nowrap;
text-overflow: ellipsis;
}
.action {
font-size: 13px;
cursor: pointer;
margin-left: 1px;
display: inline;
.text {
flex: 1;
display: inline;
margin: 0;
padding: 0;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
&.right {
float: right;
}
.action {
font-size: 13px;
cursor: pointer;
margin-left: 1px;
display: inline;
.fa {
margin-right: 5px;
&.right {
float: right;
}
.fa {
margin-right: 5px;
&:hover {
color: var(--color-primary);
}
&:hover {
color: var(--color-primary);
}
}
}
}
.edit-input ::v-deep input {
border-left: none;
border-right: none;
border-top: none;
height: 30px;
}
.edit-input ::v-deep input {
border-left: none;
border-right: none;
border-top: none;
height: 30px;
}
</style>

View File

@@ -16,7 +16,7 @@
closable
size="small"
type="info"
@click="handleTagClick(v,k)"
@click="handleTagClick(v, k)"
@close.stop="handleTagClose(k)"
>
<strong v-if="v.label">{{ v.label + ':' }}</strong>
@@ -40,7 +40,6 @@
/>
<span :class="isFocus ? 'is-focus ' : ''" class="keydown-focus">/</span>
</div>
</template>
<script>
@@ -49,8 +48,7 @@ export default {
props: {
config: {
type: Object,
default: () => {
}
default: () => {}
},
options: {
type: Array,
@@ -90,13 +88,14 @@ export default {
},
filterMaps() {
const data = {}
const keyword = 'search'
for (let key in this.filterTags) {
const value = this.filterTags[key]['value']
if (key === '') {
key = 'search'
key = keyword
}
if (key.startsWith('search')) {
data['search'] = (data.search ? data.search + ',' : '') + value
if (key.startsWith(keyword)) {
data[keyword] = (data[keyword] ? data[keyword] + ',' : '') + value
} else {
data[key] = value
}
@@ -138,7 +137,7 @@ export default {
this.emptyCount = 1
}
},
'$route'(to, from) {
$route(to, from) {
if (from.query !== to.query) {
this.filterTags = {}
if (to.query && Object.keys(to.query).length) {
@@ -169,7 +168,7 @@ export default {
// 获取url中的查询条件判断是不是包含在当前查询条件里
checkInTableColumns(options) {
const searchFieldOptions = {}
const queryInfoValues = options.map((i) => i.value)
const queryInfoValues = options.map(i => i.value)
const routeQuery = this.getUrlQuery ? this.$route?.query : {}
const routeQueryKeysLength = Object.keys(routeQuery).length
if (routeQueryKeysLength < 1) return searchFieldOptions

View File

@@ -8,7 +8,7 @@
class="left"
>
<span v-if="component === 'AutoDataZTree'" class="title">
{{ $t('AssetTree') }}
{{ title }}
</span>
<component
:is="component"
@@ -111,6 +111,13 @@ export default {
headerActions: {
type: Object,
default: () => ({})
},
title: {
// eslint-disable-next-line vue/require-prop-type-constructor
type: String,
default() {
return this.$t('AssetTree')
}
}
},
data() {

View File

@@ -26,6 +26,7 @@
import DataZTree from '../DataZTree/index.vue'
import Icon from '@/components/Widgets/Icon'
import $ from '@/utils/jquery-vendor'
import { getShowCurrentAssetValue } from '@/utils/common/index'
import { mapGetters } from 'vuex'
export default {
@@ -199,7 +200,7 @@ export default {
},
// Request URL: http://localhost/api/v1/assets/assets/?node_id=ID&show_current_asset=null&draw=2&limit=15&offset=0&_=1587022917769
onSelected: function(event, treeNode) {
const show_current_asset = this.$cookie.get('show_current_asset') || '0'
const show_current_asset = getShowCurrentAssetValue(this.$cookie)
if (!this.setting.url) {
return
}
@@ -421,12 +422,8 @@ export default {
display: inline-block;
}
.data-z-tree {
::v-deep {
.icon {
width: 10px;
margin-right: 3px;
}
}
.data-z-tree ::v-deep .icon {
width: 10px;
margin-right: 3px;
}
</style>

View File

@@ -1,20 +1,52 @@
<template>
<el-alert
v-if="enabled && !isViewed()"
:center="false"
:title="title"
class="announcement"
type="success"
@close="onClose"
>
<MarkDown :value="announcement.content" class="markdown" />
<span v-if="announcement.link">
<el-link :href="announcement.link" class="link-more" target="_blank" type="info">
{{ $t('ViewMore') }}
</el-link>
<i class="fa fa-external-link icon" />
</span>
</el-alert>
<div>
<el-dialog
v-if="enabled && showModal"
:visible.sync="dialogVisible"
:title="title"
:close-on-click-modal="false"
:close-on-press-escape="false"
:show-close="false"
width="35%"
class="announcement-dialog"
center
>
<div class="announcement-content">
<div class="content-wrapper">
<MarkDown :value="announcement.content" class="markdown" />
</div>
<div v-if="announcement.link" class="link-section">
<el-link :href="announcement.link" class="link-more" target="_blank" type="info">
{{ $t('ViewMore') }}
</el-link>
<i class="fa fa-external-link icon" />
</div>
</div>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="onModalConfirm">
{{ $t('Confirm') }}
</el-button>
</div>
</el-dialog>
<el-alert
v-if="enabled && showAlert"
:center="false"
:title="title"
class="announcement"
type="info"
@close="onAlertClose"
>
<MarkDown :value="announcement.content" class="markdown" />
<span v-if="announcement.link">
<el-link :href="announcement.link" class="link-more" target="_blank" type="info">
{{ $t('ViewMore') }}
</el-link>
<i class="fa fa-external-link icon" />
</span>
</el-alert>
</div>
</template>
<script>
@@ -26,7 +58,11 @@ export default {
components: { MarkDown },
data() {
return {
viewedKey: 'AnnouncementViewed'
viewedKey: 'AnnouncementViewed',
modalConfirmedKey: 'AnnouncementModalConfirmed',
dialogVisible: false,
modalConfirmed: false,
alertViewed: false
}
},
computed: {
@@ -58,48 +94,200 @@ export default {
const start = new Date(this.announcement.date_start)
const end = new Date(this.announcement.date_end)
return now >= start && now <= end
},
showModal() {
return !this.modalConfirmed
},
showAlert() {
return this.modalConfirmed && !this.alertViewed
}
},
watch: {
enabled: {
handler(val) {
if (val) {
this.initializeState()
this.checkAndShowDialog()
}
},
immediate: true
}
},
mounted() {
this.initializeState()
this.checkAndShowDialog()
},
methods: {
onClose() {
localStorage.setItem(this.viewedKey, this.announcement.id)
initializeState() {
this.modalConfirmed = this.isModalConfirmed()
this.alertViewed = this.isAlertViewed()
},
isViewed() {
checkAndShowDialog() {
if (this.enabled && this.showModal) {
this.dialogVisible = true
}
},
onModalConfirm() {
localStorage.setItem(this.modalConfirmedKey, this.announcement.id)
this.modalConfirmed = true
this.dialogVisible = false
this.$emit('announcement-modal-confirmed', {
id: this.announcement.id,
subject: this.announcement.subject,
confirmedAt: new Date().toISOString()
})
},
onAlertClose() {
localStorage.setItem(this.viewedKey, this.announcement.id)
this.alertViewed = true
this.$emit('announcement-read', {
id: this.announcement.id,
subject: this.announcement.subject,
readAt: new Date().toISOString()
})
},
isModalConfirmed() {
const confirmedId = localStorage.getItem(this.modalConfirmedKey)
return confirmedId === this.announcement.id
},
isAlertViewed() {
const viewedId = localStorage.getItem(this.viewedKey)
return viewedId === this.announcement.id
},
isViewed() {
return this.isAlertViewed()
}
}
}
</script>
<style lang="scss" scoped>
.announcement ::v-deep .el-alert__content {
width: 100%;
.announcement-dialog ::v-deep .el-dialog {
border-radius: 5px;
}
.announcement-main {
word-wrap: break-word;
white-space: pre-wrap;
.announcement-dialog ::v-deep .el-dialog__wrapper {
backdrop-filter: blur(4px);
}
@media (max-width: 768px) {
.announcement-dialog ::v-deep .el-dialog {
width: 95% !important;
margin: 0 auto;
}
.announcement-content {
padding: 20px 25px 15px;
.content-wrapper {
padding: 15px;
}
}
.dialog-footer {
.el-button {
padding: 10px;
font-size: 14px;
}
}
}
.announcement-dialog ::v-deep .el-dialog__header {
border-radius: 8px 8px 0 0;
padding: 10px 20px 10px 20px;
.el-dialog__title {
color: black;
font-weight: 600;
}
}
.announcement-dialog ::v-deep .el-dialog__body {
padding: 0;
}
.announcement-content {
padding: 25px 30px 20px;
.link-section {
margin-top: 20px;
padding-top: 15px;
border-top: 1px solid #e4e7ed;
text-align: center;
}
}
.dialog-footer {
display: flex;
justify-content: flex-end;
align-items: center;
.el-button {
padding: 10px 20px;
font-size: 14px;
}
}
.announcement ::v-deep .el-alert__content {
width: 100%;
}
.icon {
vertical-align: text-bottom;
color: var(--color-info) !important;
margin-left: 5px;
}
.markdown {
background-color: transparent !important;
font-size: 14px;
line-height: 1.8;
color: #2c3e50;
.link-more {
font-size: 10px;
margin-left: 10px;
border-bottom: solid 1px;
color: var(--color-info) !important;
font-size: 13px;
color: #409eff !important;
text-decoration: none;
padding: 4px 8px;
border-radius: 4px;
background: rgba(64, 158, 255, 0.1);
transition: all 0.3s;
&:hover {
background: #409eff;
color: white !important;
}
}
h1, h2, h3, h4, h5 {
margin-top: 0;
margin-bottom: 10px;
h1, h2, h3, h4, h5, h6 {
margin: 0 0 15px 0;
color: #303133;
font-weight: 600;
line-height: 1.4;
}
h1 {
font-size: 20px;
}
h2 {
font-size: 18px;
}
h3 {
font-size: 16px;
}
h4, h5, h6 {
font-size: 14px;
}
p {
margin-bottom: 16px;
line-height: 1.8;
color: #4b5563;
}
}
</style>

View File

@@ -33,7 +33,7 @@ export default {
const first = matched[0]
if (!this.isDashboard(first)) {
matched = [{ path: '/dashboard', meta: { title: 'dashboard' }}].concat(matched)
matched = [{ path: '/dashboard', meta: { title: 'dashboard' } }].concat(matched)
}
this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)

View File

@@ -1,6 +1,6 @@
<script>
export default {
name: 'Index',
name: 'Icon',
props: {
icon: {
type: String,

View File

@@ -140,6 +140,7 @@ export default {
margin-left: 4px;
padding: 5px 10px;
border: 1px solid #DCDFE6;
border-radius: 2px;
@import "~github-markdown-css/github-markdown-light.css";
}

View File

@@ -37,3 +37,4 @@ export { default as Pagination } from './Table/Pagination'
export { default as Tooltip } from './Widgets/Tooltip'
export { default as ResourceActivity } from './Apps/ResourceActivity'
export { default as MarkDown } from './Widgets/MarkDown'
export { default as VariablesHelpTextDialog } from './Apps/VariablesHelpTextDialog'

View File

@@ -1,6 +1,6 @@
// i18n.js
import Vue from 'vue'
import locale from 'elementui-lts/lib/locale'
import locale from 'element-ui/lib/locale'
import VueI18n from 'vue-i18n'
import messages from './langs'
import date from './date'
@@ -54,7 +54,7 @@ export async function fetchTranslationsFromAPI() {
}
}
} catch (error) {
alert(error)
console.log(error)
} finally {
await store.dispatch('app/setI18nLoaded', true)
}

View File

@@ -1,45 +1,44 @@
import zhLocale from 'elementui-lts/lib/locale/lang/zh-CN'
import zhTWLocale from 'elementui-lts/lib/locale/lang/zh-TW'
import enLocale from 'elementui-lts/lib/locale/lang/en'
import jaLocale from 'elementui-lts/lib/locale/lang/ja'
import ptBrLocale from 'elementui-lts/lib/locale/lang/pt-br'
import esLocale from 'elementui-lts/lib/locale/lang/es'
import ruLocale from 'elementui-lts/lib/locale/lang/ru-RU'
import koLocale from 'elementui-lts/lib/locale/lang/ko'
import zh from './zh.json'
import zhHant from './zh_hant.json'
import zh_hant from './zh_hant.json'
import en from './en.json'
import ja from './ja.json'
const messages = {
zh: {
...zhLocale,
...zh
},
zh_hant: {
...zhTWLocale,
...zhHant
},
en: {
...enLocale,
...en
},
ja: {
...jaLocale,
...ja
},
pt_br: {
...ptBrLocale
},
es: {
...esLocale
},
ru: {
...ruLocale
},
ko: {
...koLocale
// Map app locales to Element-UI locale file names
const elementLocaleNameByAppLocale = {
zh: 'zh-CN',
zh_hant: 'zh-TW',
en: 'en',
ja: 'ja',
pt_br: 'pt-br',
es: 'es',
ru: 'ru-RU',
ko: 'ko',
vi: 'vi'
}
function loadElementLocale(localeName) {
try {
// eslint-disable-next-line import/no-dynamic-require, global-require
const mod = require(`element-ui/lib/locale/lang/${localeName}`)
return (mod && (mod.default || mod)) || {}
} catch (e) {
return {}
}
}
const appLocaleMessages = {
zh,
zh_hant,
en,
ja
}
const messages = Object.keys(elementLocaleNameByAppLocale).reduce((acc, appLocale) => {
const elementLocaleName = elementLocaleNameByAppLocale[appLocale]
const elementLocale = loadElementLocale(elementLocaleName)
const appMessages = appLocaleMessages[appLocale] || {}
acc[appLocale] = { ...elementLocale, ...appMessages }
return acc
}, {})
export default messages

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free v5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M512 176.001C512 273.203 433.202 352 336 352c-11.22 0-22.19-1.062-32.827-3.069l-24.012 27.014A23.999 23.999 0 0 1 261.223 384H224v40c0 13.255-10.745 24-24 24h-40v40c0 13.255-10.745 24-24 24H24c-13.255 0-24-10.745-24-24v-78.059c0-6.365 2.529-12.47 7.029-16.971l161.802-161.802C163.108 213.814 160 195.271 160 176 160 78.798 238.797.001 335.999 0 433.488-.001 512 78.511 512 176.001zM336 128c0 26.51 21.49 48 48 48s48-21.49 48-48-21.49-48-48-48-48 21.49-48 48z"/></svg>

After

Width:  |  Height:  |  Size: 691 B

View File

@@ -1,8 +1 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="40px" height="48px" viewBox="0 0 40 48" version="1.1" xmlns="http://www.w3.org/2000/svg"
>
<path d="M36.0001406,20.0002344 L36.0001406,16.000375 C36.0001406,7.17752804 28.8226126,0 20.0002344,0 C11.1778562,0 4.00032813,7.17752804 4.00032813,15.9999062 L4.00032813,19.9997656 L0,19.9997656 L0,48.0001875 L40,48.0001875 L40,20.0002344 L36.0001406,20.0002344 Z M8.0001875,15.9999062 C8.0001875,9.3830054 13.3833335,3.99985937 20.0002344,3.99985937 C26.6171352,3.99985937 32.0002813,9.3830054 32.0002813,15.9999062 L32.0002813,19.9997656 L8.0001875,19.9997656 L8.0001875,15.9999062 Z M36.0006094,44.0003281 L4.00032813,44.0003281 L4.00032813,24.0000938 L36.0006094,24.0000938 L36.0006094,44.0003281 Z"
id="形状"></path>
<path d="M20.0002344,40 C22.2094618,40 24.0000938,38.2088993 24.0000938,36.0001406 C24.0000938,34.5231036 23.1905593,33.2476299 21.9999297,32.5548147 L21.9999297,27.9999531 L18.0000703,27.9999531 L18.0000703,32.5548147 C16.8094407,33.2476299 15.9999062,34.5231036 15.9999062,36.0001406 C16.000375,38.209368 17.791007,40 20.0002344,40 L20.0002344,40 Z"
id="路径"></path>
</svg>
<svg width="40" height="48" xmlns="http://www.w3.org/2000/svg"><path d="M36 20v-4c0-8.822-7.177-16-16-16C11.178 0 4 7.178 4 16v4H0v28h40V20h-4zM8 16C8 9.383 13.383 4 20 4s12 5.383 12 12v4H8v-4zm28 28H4V24h32v20z"/><path d="M20 40a4 4 0 0 0 4-4c0-1.477-.81-2.752-2-3.445V28h-4v4.555c-1.19.693-2 1.968-2 3.445a4 4 0 0 0 4 4z"/></svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 331 B

View File

@@ -1,22 +1 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="40px" height="41px" viewBox="0 0 40 41" version="1.1" xmlns="http://www.w3.org/2000/svg"
>
<path d="M40,11.3258427 L40,11.3258427 C40,12.2247191 39.5505618,12.6741573 38.6516854,12.6741573 L33.9325842,12.6741573 C33.0337078,12.6741573 32.5842696,12.2247191 32.5842696,11.3258427 L32.5842696,11.3258427 C32.5842696,10.4269663 33.0337078,9.97752808 33.9325842,9.97752808 L38.6516854,9.97752808 C39.5505618,9.97752808 40,10.4269663 40,11.3258427 Z"
id="路径"></path>
<path d="M40,28.0449438 L40,28.0449438 C40,28.9438202 39.5505618,29.3932584 38.6516854,29.3932584 L33.9325842,29.3932584 C33.0337078,29.3932584 32.5842696,28.9438202 32.5842696,28.0449438 L32.5842696,28.0449438 C32.5842696,27.1460674 33.0337078,26.6966292 33.9325842,26.6966292 L38.6516854,26.6966292 C39.5505618,26.6966292 40,27.1460674 40,28.0449438 Z"
id="路径"></path>
<path d="M7.41573034,28.0449438 L7.41573034,28.0449438 C7.41573034,28.9438202 6.96629214,29.3932584 6.06741574,29.3932584 L1.34831461,29.3932584 C0.449438202,29.3932584 0,28.9438202 0,28.0449438 L0,28.0449438 C0,27.1460674 0.449438202,26.6966292 1.34831461,26.6966292 L6.06741574,26.6966292 C6.96629214,26.6966292 7.41573034,27.1460674 7.41573034,28.0449438 Z"
id="路径"></path>
<path d="M7.41573034,11.3258427 L7.41573034,11.3258427 C7.41573034,12.2247191 6.96629214,12.6741573 6.06741574,12.6741573 L1.34831461,12.6741573 C0.449438202,12.6741573 0,12.2247191 0,11.3258427 L0,11.3258427 C0,10.4269663 0.449438202,9.97752808 1.34831461,9.97752808 L6.06741574,9.97752808 C6.96629214,9.97752808 7.41573034,10.4269663 7.41573034,11.3258427 Z"
id="路径"></path>
<path d="M20.1348314,0 L20.1348314,0 C21.0337078,0 21.483146,0.449438202 21.483146,1.34831461 L21.483146,6.06741574 C21.483146,6.96629214 21.0337078,7.41573034 20.1348314,7.41573034 L20.1348314,7.41573034 C19.2359551,7.41573034 18.7865169,6.96629214 18.7865169,6.06741574 L18.7865169,1.34831461 C18.7865169,0.449438202 19.2359551,0 20.1348314,0 Z"
id="路径"></path>
<path d="M20.1348314,15.4606742 L20.1348314,15.4606742 C21.0337078,15.4606742 21.483146,15.9101124 21.483146,16.8089888 L21.483146,21.5280898 C21.483146,22.4269662 21.0337078,22.8764044 20.1348314,22.8764044 L20.1348314,22.8764044 C19.2359551,22.8764044 18.7865169,22.4269662 18.7865169,21.5280898 L18.7865169,16.8089888 C18.7865169,15.9101124 19.2359551,15.4606742 20.1348314,15.4606742 Z"
id="路径"></path>
<path d="M20.1348314,32.7191012 L20.1348314,32.7191012 C21.0337078,32.7191012 21.483146,33.1685394 21.483146,34.0674158 L21.483146,38.7865168 C21.483146,39.6853932 21.0337078,40.1348314 20.1348314,40.1348314 L20.1348314,40.1348314 C19.2359551,40.1348314 18.7865169,39.6853932 18.7865169,38.7865168 L18.7865169,34.0674158 C18.7865169,33.1685394 19.2359551,32.7191012 20.1348314,32.7191012 Z"
id="路径"></path>
<path d="M8.04494382,24.5842696 C7.8960131,24.5842696 7.7752809,24.7050018 7.7752809,24.8539326 L7.7752809,31.235955 C7.7752809,31.3848858 7.8960131,31.505618 8.04494382,31.505618 L32.2247192,31.505618 C32.3736498,31.505618 32.494382,31.3848858 32.494382,31.235955 L32.494382,24.8539326 C32.494382,24.7050018 32.3736498,24.5842696 32.2247192,24.5842696 L8.04494382,24.5842696 Z M8.04494382,21.8876404 L32.2247192,21.8876404 C33.8629214,21.8876404 35.1910112,23.2157304 35.1910112,24.8539326 L35.1910112,31.235955 C35.1910112,32.8741574 33.8629214,34.2022472 32.2247192,34.2022472 L8.04494382,34.2022472 C6.40674158,34.2022472 5.07865168,32.8741574 5.07865168,31.235955 L5.07865168,24.8539326 C5.07865168,23.2157304 6.40674158,21.8876404 8.04494382,21.8876404 Z M8.04494382,7.86516854 C7.8960131,7.86516854 7.7752809,7.98590074 7.7752809,8.13483146 L7.7752809,14.5168539 C7.7752809,14.6657847 7.8960131,14.7865169 8.04494382,14.7865169 L32.2247192,14.7865169 C32.3736498,14.7865169 32.494382,14.6657847 32.494382,14.5168539 L32.494382,8.13483146 C32.494382,7.98590074 32.3736498,7.86516854 32.2247192,7.86516854 L8.04494382,7.86516854 Z M8.04494382,5.16853932 L32.2247192,5.16853932 C33.8629214,5.16853932 35.1910112,6.49662922 35.1910112,8.13483146 L35.1910112,14.5168539 C35.1910112,16.1550562 33.8629214,17.4831461 32.2247192,17.4831461 L8.04494382,17.4831461 C6.40674158,17.4831461 5.07865168,16.1550562 5.07865168,14.5168539 L5.07865168,8.13483146 C5.07865168,6.49662922 6.40674158,5.16853932 8.04494382,5.16853932 Z"
id="形状"></path>
<path d="M29.1578876,12.6634607 C29.6358192,12.6030981 30.0452276,12.2923121 30.2318532,11.8482026 C30.4184786,11.4040932 30.35396,10.8941516 30.0626068,10.5105169 C29.771344,10.1268666 29.2975172,9.92776542 28.8196404,9.98822472 C28.3417088,10.0485873 27.9323004,10.3593733 27.745675,10.8034828 C27.5590494,11.2475922 27.6235682,11.7575338 27.9149214,12.1411685 C28.206184,12.5248188 28.680011,12.72392 29.1578876,12.6634607 L29.1578876,12.6634607 Z M29.1578876,29.3825618 C29.6358192,29.3221992 30.0452276,29.0114132 30.2318532,28.5673038 C30.4184786,28.1231944 30.35396,27.6132526 30.0626068,27.229618 C29.771344,26.8459678 29.2975172,26.6468666 28.8196404,26.7073258 C28.3417088,26.7676884 27.9323004,27.0784744 27.745675,27.5225838 C27.5590494,27.9666934 27.6235682,28.476635 27.9149214,28.8602696 C28.206184,29.24392 28.680011,29.443021 29.1578876,29.3825618 L29.1578876,29.3825618 Z"
id="形状"></path>
</svg>
<svg width="40" height="41" xmlns="http://www.w3.org/2000/svg"><path d="M40 11.326c0 .899-.45 1.348-1.348 1.348h-4.72c-.898 0-1.348-.45-1.348-1.348 0-.899.45-1.348 1.349-1.348h4.719c.899 0 1.348.449 1.348 1.348zM40 28.045c0 .899-.45 1.348-1.348 1.348h-4.72c-.898 0-1.348-.45-1.348-1.348 0-.899.45-1.348 1.349-1.348h4.719c.899 0 1.348.45 1.348 1.348zM7.416 28.045c0 .899-.45 1.348-1.349 1.348H1.348C.45 29.393 0 28.943 0 28.045c0-.899.45-1.348 1.348-1.348h4.72c.898 0 1.348.45 1.348 1.348zM7.416 11.326c0 .899-.45 1.348-1.349 1.348H1.348C.45 12.674 0 12.224 0 11.326c0-.899.45-1.348 1.348-1.348h4.72c.898 0 1.348.449 1.348 1.348zM20.135 0c.899 0 1.348.45 1.348 1.348v4.72c0 .898-.45 1.348-1.348 1.348-.899 0-1.348-.45-1.348-1.349V1.348C18.787.45 19.236 0 20.135 0zM20.135 15.46c.899 0 1.348.45 1.348 1.349v4.72c0 .898-.45 1.347-1.348 1.347-.899 0-1.348-.449-1.348-1.348V16.81c0-.899.449-1.348 1.348-1.348zM20.135 32.72c.899 0 1.348.449 1.348 1.347v4.72c0 .898-.45 1.348-1.348 1.348-.899 0-1.348-.45-1.348-1.348v-4.72c0-.898.449-1.348 1.348-1.348z"/><path d="M8.045 24.584a.27.27 0 0 0-.27.27v6.382c0 .149.121.27.27.27h24.18a.27.27 0 0 0 .27-.27v-6.382a.27.27 0 0 0-.27-.27H8.045zm0-2.696h24.18a2.966 2.966 0 0 1 2.966 2.966v6.382a2.966 2.966 0 0 1-2.966 2.966H8.045a2.966 2.966 0 0 1-2.966-2.966v-6.382a2.966 2.966 0 0 1 2.966-2.966zm0-14.023a.27.27 0 0 0-.27.27v6.382c0 .149.121.27.27.27h24.18a.27.27 0 0 0 .27-.27V8.135a.27.27 0 0 0-.27-.27H8.045zm0-2.696h24.18a2.966 2.966 0 0 1 2.966 2.966v6.382a2.966 2.966 0 0 1-2.966 2.966H8.045a2.966 2.966 0 0 1-2.966-2.966V8.135a2.966 2.966 0 0 1 2.966-2.966z"/><path d="M29.158 12.663a1.348 1.348 0 1 0-.338-2.675 1.348 1.348 0 0 0 .338 2.675zm0 16.72a1.348 1.348 0 1 0-.338-2.676 1.348 1.348 0 0 0 .338 2.676z"/></svg>

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -1,5 +1 @@
<svg t="1736148692584" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="41075" width="200" height="200">
<path d="M512.034996 927.992188c-229.350883 0-415.937195-186.646305-415.937196-415.927196 0-229.290891 186.586312-415.937195 415.937196-415.937196s415.927197 186.646305 415.927196 415.937196c0 229.280892-186.576314 415.927197-415.927196 415.927196z m0-927.862205C229.330886 0.129983 0.099987 229.360882 0.099987 512.064992s229.230898 511.935008 511.935009 511.935008 511.935008-229.2209 511.935008-511.935008c0-282.70411-229.2209-511.935008-511.935008-511.935009z m209.893353 352.33527c-12.948356-0.539931-26.016697 3.789519-35.895443 13.728258L464.03109 588.195327 337.977093 462.131331c-9.878746-9.878746-22.947087-14.208196-35.835451-13.728257-11.628524 0.479939-23.127064 4.819388-32.045931 13.728257-8.848877 8.848877-13.188326 20.417408-13.668265 32.045932-0.479939 12.888364 3.849511 25.956705 13.668265 35.83545l159.969691 159.959693c9.388808 9.338814 21.677248 14.028219 33.905695 14.028219 12.28844 0 24.57688-4.699403 33.905696-14.028219l255.967504-255.967504c9.878746-9.878746 14.218195-22.947087 13.738256-35.835451-0.479939-11.628524-4.819388-23.187056-13.738256-32.045932-8.908869-8.838878-20.297423-13.238319-31.915948-13.658266z"
fill="#515151" p-id="41076"></path>
</svg>
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><path d="M512.035 927.992c-229.35 0-415.937-186.646-415.937-415.927 0-229.29 186.586-415.937 415.937-415.937s415.927 186.646 415.927 415.937c0 229.28-186.576 415.927-415.927 415.927zm0-927.862C229.331.13.1 229.36.1 512.065S229.33 1024 512.035 1024s511.935-229.22 511.935-511.935C1023.97 229.361 794.75.13 512.035.13zm209.893 352.335c-12.948-.54-26.016 3.79-35.895 13.729L464.03 588.195 337.977 462.131c-9.879-9.878-22.947-14.208-35.835-13.728-11.629.48-23.127 4.82-32.046 13.728-8.85 8.85-13.189 20.418-13.669 32.046-.48 12.889 3.85 25.957 13.669 35.836l159.97 159.96C439.453 699.31 451.742 704 463.97 704c12.289 0 24.577-4.7 33.906-14.029l255.967-255.967c9.879-9.879 14.218-22.947 13.739-35.836-.48-11.628-4.82-23.187-13.739-32.045-8.909-8.84-20.297-13.239-31.916-13.659z" fill="currentColor"/></svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 903 B

View File

@@ -1,10 +1 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="138px" height="134px" viewBox="0 0 138 134" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>activity</title>
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="activity" fill="#3E3A39" fill-rule="nonzero">
<path d="M125.454545,123.012 C125.454545,123.30102 125.310273,123.469176 125.435727,123.484941 L12.7900909,123.553255 C12.7399091,123.521725 12.5454545,123.332549 12.5454545,123.012 L12.5454545,44.6614118 L125.454545,44.6614118 L125.454545,123.012 Z M12.5454545,18.865098 C12.5454545,18.5813333 12.6709091,18.4131765 12.5642727,18.386902 L37.6363636,18.386902 L37.6363636,21.0196078 C37.6363636,23.9218101 40.4447593,26.2745098 43.9090909,26.2745098 C47.3734225,26.2745098 50.1818182,23.9218101 50.1818182,21.0196078 L50.1818182,18.3921569 L87.8181818,18.3921569 L87.8181818,21.0196078 C87.8181818,23.9218101 90.6265775,26.2745098 94.0909091,26.2745098 C97.5552407,26.2745098 100.363636,23.9218101 100.363636,21.0196078 L100.363636,18.3921569 L125.260091,18.3921569 C125.385308,18.5275639 125.454545,18.6938135 125.454545,18.865098 L125.454545,34.1568627 L12.5454545,34.1568627 L12.5454545,18.865098 Z M125.423182,7.88235294 L100.363636,7.88235294 L100.363636,5.25490196 C100.363636,2.35269975 97.5552407,0 94.0909091,0 C90.6265775,0 87.8181818,2.35269975 87.8181818,5.25490196 L87.8181818,7.88235294 L50.1818182,7.88235294 L50.1818182,5.25490196 C50.1818182,2.35269975 47.3734225,0 43.9090909,0 C40.4447593,0 37.6363636,2.35269975 37.6363636,5.25490196 L37.6363636,7.88235294 L12.489,7.88235294 C5.60154545,7.88235294 0,12.811451 0,18.865098 L0,123.017255 C0,129.076157 5.60781818,134 12.4952727,134 L125.504727,134 C132.392182,134 138,129.076157 138,123.017255 L138,18.865098 C138,12.8061961 132.360818,7.87709804 125.423182,7.87709804 L125.423182,7.88235294 Z" id="形状"></path>
<path d="M44.3,76.5714286 L94.7,76.5714286 C98.1793939,76.5714286 101,74.2049337 101,71.2857143 C101,68.3664949 98.1793939,66 94.7,66 L44.3,66 C40.8206061,66 38,68.3664949 38,71.2857143 C38,74.2049337 40.8206061,76.5714286 44.3,76.5714286 M44.3,103 L94.7,103 C98.1793939,103 101,100.633505 101,97.7142857 C101,94.7950663 98.1793939,92.4285714 94.7,92.4285714 L44.3,92.4285714 C40.8206061,92.4285714 38,94.7950663 38,97.7142857 C38,100.633505 40.8206061,103 44.3,103" id="形状"></path>
</g>
</g>
</svg>
<svg width="138" height="134" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" fill-rule="nonzero"><path d="M125.455 123.012c0 .289-.145.457-.02.473l-112.645.068a.684.684 0 0 1-.245-.541v-78.35h112.91v78.35zM12.545 18.865c0-.284.126-.452.02-.478h25.071v2.633c0 2.902 2.809 5.255 6.273 5.255 3.464 0 6.273-2.353 6.273-5.255v-2.628h37.636v2.628c0 2.902 2.809 5.255 6.273 5.255 3.464 0 6.273-2.353 6.273-5.255v-2.628h24.896a.697.697 0 0 1 .195.473v15.292H12.545V18.865zM125.423 7.882h-25.06V5.255c0-2.902-2.808-5.255-6.272-5.255-3.464 0-6.273 2.353-6.273 5.255v2.627H50.182V5.255C50.182 2.353 47.373 0 43.909 0c-3.464 0-6.273 2.353-6.273 5.255v2.627H12.49C5.602 7.882 0 12.812 0 18.865v104.152C0 129.077 5.608 134 12.495 134h113.01c6.887 0 12.495-4.924 12.495-10.983V18.865c0-6.059-5.64-10.988-12.577-10.988v.005z"/><path d="M44.3 76.571h50.4c3.48 0 6.3-2.366 6.3-5.285 0-2.92-2.82-5.286-6.3-5.286H44.3c-3.48 0-6.3 2.366-6.3 5.286 0 2.919 2.82 5.285 6.3 5.285m0 26.429h50.4c3.48 0 6.3-2.366 6.3-5.286 0-2.919-2.82-5.285-6.3-5.285H44.3c-3.48 0-6.3 2.366-6.3 5.285 0 2.92 2.82 5.286 6.3 5.286"/></g></svg>

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,8 +1 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="40px" height="40px" viewBox="0 0 40 40" version="1.1" xmlns="http://www.w3.org/2000/svg"
>
<path d="M20,2.99999997 C29.3888408,2.99999997 37,10.6111592 37,20 C37,29.3888408 29.3888408,37 20,37 C10.6111592,37 2.99999997,29.3888408 2.99999997,20 C2.99999997,10.6111592 10.6111592,2.99999997 20,2.99999997 M20,0 C8.95430504,0 0,8.95430504 0,20 C0,31.045695 8.95430504,40 20,40 C31.045695,40 40,31.045695 40,20 C40,8.95430504 31.045695,0 20,0 L20,0 Z"
id="形状"></path>
<path d="M14.5,38.5 C13.6715729,38.5 12.9998649,37.8284271 12.9998649,37 L12.9998649,12.5 C12.9950101,11.9783475 13.2632038,11.4920757 13.7070718,11.217982 C14.1509399,10.9438883 14.7058314,10.9218957 15.17,11.16 L29.87,18.51 C30.376377,18.7647348 30.695908,19.2831601 30.695908,19.85 C30.695908,20.4168398 30.376377,20.9352652 29.87,21.19 L16,28.13 L16,37 C16,37.8284271 15.3284271,38.5 14.5,38.5 L14.5,38.5 Z M16,14.93 L16,24.77 L25.85,19.85 L16,14.93 Z"
id="形状"></path>
</svg>
<svg width="40" height="40" xmlns="http://www.w3.org/2000/svg"><path d="M20 3c9.389 0 17 7.611 17 17s-7.611 17-17 17S3 29.389 3 20 10.611 3 20 3m0-3C8.954 0 0 8.954 0 20s8.954 20 20 20 20-8.954 20-20S31.046 0 20 0z"/><path d="M14.5 38.5A1.5 1.5 0 0 1 13 37V12.5a1.49 1.49 0 0 1 2.17-1.34l14.7 7.35a1.5 1.5 0 0 1 0 2.68L16 28.13V37a1.5 1.5 0 0 1-1.5 1.5zM16 14.93v9.84l9.85-4.92L16 14.93z"/></svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 396 B

View File

@@ -1,6 +1 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="40px" height="40px" viewBox="0 0 40 40" version="1.1" xmlns="http://www.w3.org/2000/svg"
>
<path d="M20.5597162,35.9666034 L40,39.1471674 L40,21.1860823 L20.5597162,21.1860823 L20.5597162,35.9680367 L20.5597162,35.9666034 Z M23.7847135,24.4110797 L36.7750027,24.4110797 L36.7750027,35.3402372 L23.7847135,33.2346723 L23.7847135,24.4110797 Z M20.5597162,3.22499731 L20.5597162,17.961085 L40,17.961085 L40,0 L20.5597162,3.22499731 Z M36.7735694,14.7360877 L23.7832802,14.7360877 L23.7832802,5.95692837 L36.7735694,3.80693016 L36.7735694,14.7360877 Z M0,17.961085 L16.4388863,17.961085 L16.4388863,3.76249686 L0,6.49442792 L0,17.961085 Z M3.22499731,9.22635898 L13.213889,7.56942703 L13.213889,14.7360877 L3.22499731,14.7360877 L3.22499731,9.22635898 Z M0,32.741606 L16.4388863,35.4291038 L16.4388863,21.184649 L0,21.184649 L0,32.741606 Z M3.22499731,24.4110797 L13.213889,24.4110797 L13.213889,31.6221736 L3.22499731,30.009675 L3.22499731,24.4110797 L3.22499731,24.4110797 Z"
id="形状"></path>
</svg>
<svg width="40" height="40" xmlns="http://www.w3.org/2000/svg"><path d="M20.56 35.967L40 39.147v-17.96H20.56v14.781-.001zm3.225-11.556h12.99v10.93l-12.99-2.106V24.41zM20.56 3.225v14.736H40V0L20.56 3.225zm16.214 11.511h-12.99v-8.78l12.99-2.15v10.93zM0 17.961h16.439V3.762L0 6.494v11.467zm3.225-8.735l9.989-1.657v7.167H3.225v-5.51zM0 32.742l16.439 2.687V21.185H0v11.557zm3.225-8.33h9.989v7.21L3.225 30.01V24.41z"/></svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 418 B

View File

@@ -1 +1 @@
<svg t="1719396627639" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6265" width="40" height="40"><path d="M450.56 143.36m40.96 0l0 0q40.96 0 40.96 40.96l0 573.44q0 40.96-40.96 40.96l0 0q-40.96 0-40.96-40.96l0-573.44q0-40.96 40.96-40.96Z" fill="#000000" p-id="6266"></path><path d="M492.58496 796.22144l203.22304-203.22304a40.96 40.96 0 1 1 57.91744 57.93792L522.0352 882.62656c-0.8192 0.8192-1.6384 1.57696-2.49856 2.29376a40.96 40.96 0 0 1-55.95136-1.8432L231.87456 651.38688a40.96 40.96 0 0 1 57.93792-57.93792l202.752 202.77248z" fill="#000000" p-id="6267"></path></svg>
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="40" height="40"><path d="M491.52 143.36q40.96 0 40.96 40.96v573.44q0 40.96-40.96 40.96t-40.96-40.96V184.32q0-40.96 40.96-40.96z" fill="currentColor"/><path d="M492.585 796.221l203.223-203.223a40.96 40.96 0 1 1 57.917 57.938l-231.69 231.69c-.819.82-1.638 1.578-2.498 2.294a40.96 40.96 0 0 1-55.952-1.843l-231.71-231.69a40.96 40.96 0 0 1 57.937-57.938l202.752 202.772z" fill="currentColor"/></svg>

Before

Width:  |  Height:  |  Size: 621 B

After

Width:  |  Height:  |  Size: 479 B

View File

@@ -1,4 +1 @@
<svg width="30px" height="26.3461538px" viewBox="0 0 30 26.3461538" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path d="M11.1,10.5534309 L29.1,10.5534309 C29.2656854,10.5534309 29.4,10.4193903 29.4,10.2540428 L29.4,8.15832605 C29.4,7.99297856 29.2656854,7.85893794 29.1,7.85893794 L11.1,7.85893794 C10.9343146,7.85893794 10.8,7.99297856 10.8,8.15832605 L10.8,10.2540428 C10.8,10.4193903 10.9343146,10.5534309 11.1,10.5534309 Z M10.8,18.1878278 C10.8,18.3531753 10.9343146,18.4872159 11.1,18.4872159 L29.1,18.4872159 C29.2656854,18.4872159 29.4,18.3531753 29.4,18.1878278 L29.4,16.092111 C29.4,15.9267635 29.2656854,15.7927229 29.1,15.7927229 L11.1,15.7927229 C10.9343146,15.7927229 10.8,15.9267635 10.8,16.092111 L10.8,18.1878278 Z M29.7,0 L0.3,0 C0.134314575,0 0,0.134040623 0,0.299388112 L0,2.3951049 C0,2.56045238 0.134314575,2.69449301 0.3,2.69449301 L29.7,2.69449301 C29.8656854,2.69449301 30,2.56045238 30,2.3951049 L30,0.299388112 C30,0.134040623 29.8656854,0 29.7,0 Z M29.7,23.6516608 L0.3,23.6516608 C0.134314575,23.6516608 0,23.7857015 0,23.951049 L0,26.0467657 C0,26.2121132 0.134314575,26.3461538 0.3,26.3461538 L29.7,26.3461538 C29.8656854,26.3461538 30,26.2121132 30,26.0467657 L30,23.951049 C30,23.7857015 29.8656854,23.6516608 29.7,23.6516608 Z M1.14,18.0418761 L7.00125,13.4350415 C7.0817391,13.3726549 7.12882814,13.2766545 7.12882814,13.1749481 C7.12882814,13.0732417 7.0817391,12.9772413 7.00125,12.9148547 L1.14,8.30427775 C1.04005746,8.22586751 0.904157336,8.21092968 0.789510177,8.26575273 C0.674863019,8.32057578 0.601381695,8.43563758 0.599999983,8.5625 L0.599999983,17.7799115 C0.599999983,17.907449 0.672899333,18.0238118 0.787836917,18.0795703 C0.902774501,18.1353287 1.03952561,18.1206914 1.14,18.0418761 Z"
id="形状"></path>
</svg>
<svg width="30" height="26.346" xmlns="http://www.w3.org/2000/svg"><path d="M11.1 10.553h18a.3.3 0 0 0 .3-.299V8.158a.3.3 0 0 0-.3-.3h-18a.3.3 0 0 0-.3.3v2.096a.3.3 0 0 0 .3.3zm-.3 7.635a.3.3 0 0 0 .3.3h18a.3.3 0 0 0 .3-.3v-2.096a.3.3 0 0 0-.3-.3h-18a.3.3 0 0 0-.3.3v2.096zM29.7 0H.3a.3.3 0 0 0-.3.3v2.095a.3.3 0 0 0 .3.3h29.4a.3.3 0 0 0 .3-.3V.3A.3.3 0 0 0 29.7 0zm0 23.652H.3a.3.3 0 0 0-.3.299v2.096a.3.3 0 0 0 .3.3h29.4a.3.3 0 0 0 .3-.3V23.95a.3.3 0 0 0-.3-.3zm-28.56-5.61l5.861-4.607a.33.33 0 0 0 0-.52L1.14 8.305a.334.334 0 0 0-.54.258v9.217a.333.333 0 0 0 .54.262z"/></svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 579 B

View File

@@ -1 +1 @@
<svg t="1719396465966" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4247" width="40" height="40"><path d="M512 927.8464a32 32 0 0 1-32-31.8464V203.3664a32 32 0 0 1 64 0V896a32 32 0 0 1-32 31.8464z" fill="#2C2C2C" p-id="4248"></path><path d="M766.464 458.8032a31.8976 31.8976 0 0 1-22.6304-9.3696L512 217.6 280.1664 449.4336a32 32 0 1 1-45.2608-45.2608L512 127.0784l277.0944 277.0944a32 32 0 0 1-22.6304 54.6304z" fill="#2C2C2C" p-id="4249"></path></svg>
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="40" height="40"><path d="M512 927.846A32 32 0 0 1 480 896V203.366a32 32 0 0 1 64 0V896a32 32 0 0 1-32 31.846z" fill="currentColor"/><path d="M766.464 458.803a31.898 31.898 0 0 1-22.63-9.37L512 217.6 280.166 449.434a32 32 0 1 1-45.26-45.261L512 127.078l277.094 277.095a32 32 0 0 1-22.63 54.63z" fill="currentColor"/></svg>

Before

Width:  |  Height:  |  Size: 501 B

After

Width:  |  Height:  |  Size: 405 B

View File

@@ -1 +1 @@
<svg t="1718268187955" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7725" width="40" height="40"><path d="M14.278687 494.72555121L312.91147481 788.51184055l0-172.82492782L711.08852519 615.68691273 711.08852519 788.51184055 1009.721313 494.72555121 711.08852519 235.48815945l0 172.82492782-398.17705038 0 0-172.82492782-298.63278781 259.23739176z" fill="#2c2c2c" p-id="7726"></path></svg>
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="40" height="40"><path d="M14.279 494.726L312.91 788.512V615.687H711.09v172.825l298.632-293.786L711.09 235.488v172.825H312.91V235.488L14.28 494.726z" fill="currentColor"/></svg>

Before

Width:  |  Height:  |  Size: 435 B

After

Width:  |  Height:  |  Size: 260 B

View File

@@ -1,8 +1 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="40px" height="35px" viewBox="0 0 40 35" version="1.1" xmlns="http://www.w3.org/2000/svg"
>
<path d="M20,34.1025641 C18.974359,34.1025641 18.2051282,33.5897436 17.6923077,32.8205128 L17.4358974,32.5641025 L8.97435897,32.5641025 C8.46153847,32.5641025 7.69230768,32.051282 7.69230771,31.2820513 C7.69230775,30.5128205 8.46153847,30.2564103 8.97435897,30.2564102 L17.6923077,30.2564102 C17.9487179,29.7435897 18.2051282,29.4871795 18.7179487,29.2307692 L18.974359,28.974359 L18.974359,24.8717949 L1.02564105,24.8717949 C2.91305441e-15,24.8717949 2.91305441e-15,24.3589744 2.91305441e-15,24.1025641 L2.91305441e-15,0.512820504 C2.91305441e-15,0.256410252 0.512820504,0 1.02564105,0 L38.974359,0 C40,0 40,0.512820504 40,0.512820504 L40,24.3589744 C40,24.6153846 39.4871795,25.1282051 38.974359,25.1282051 L21.025641,25.1282051 L21.025641,28.974359 L21.2820513,29.2307692 C21.7948718,29.4871795 22.051282,29.7435897 22.3076923,30.2564102 L22.5641026,30.5128205 L31.2820513,30.5128205 C31.7948718,30.5128205 32.3076923,31.025641 32.3076923,31.7948718 C32.3076923,32.5641026 31.7948718,32.8205128 31.2820513,32.8205128 L22.3076923,32.8205128 C21.7948718,33.8461538 21.025641,34.1025641 20,34.1025641 Z M2.05128205,22.8205128 L37.9487179,22.8205128 L37.9487179,2.30769231 L2.05128205,2.05128205 L2.05128205,11.2820513 L36.6666666,11.2820513 L36.6666666,13.3333333 L2.05128205,13.3333333 L2.05128205,22.8205128 L2.05128205,22.8205128 Z M33.3333333,19.4871795 L33.3333333,17.1794872 L35.3846154,17.1794872 L35.3846154,19.4871795 L33.3333333,19.4871795 Z M33.3333333,7.94871796 L33.3333333,5.64102566 L35.3846154,5.64102566 L35.3846154,7.94871796 L33.3333333,7.94871796 Z"
id="形状"></path>
<path d="M20,34.1025641 C18.974359,34.1025641 18.2051282,33.5897436 17.6923077,32.8205128 L17.4358974,32.5641025 L8.97435897,32.5641025 C8.46153847,32.5641025 7.94871796,32.051282 7.94871796,31.5384615 C7.94871796,31.025641 8.46153847,30.5128205 8.97435897,30.5128205 L17.4358974,30.5128205 L17.6923077,30.2564102 C17.948718,29.7435897 18.2051282,29.4871795 18.7179487,29.2307692 L18.974359,28.974359 L18.974359,24.6153846 L21.025641,24.6153846 L21.025641,28.974359 L21.2820513,29.2307692 C21.7948718,29.4871795 22.051282,29.7435897 22.3076923,30.2564102 L22.5641026,30.5128205 L31.2820513,30.5128205 C31.7948718,30.5128205 32.3076923,31.025641 32.3076923,31.5384615 C32.3076923,32.0512821 31.7948718,32.5641025 31.2820513,32.5641025 L22.5641026,32.5641025 L22.3076923,32.8205128 C21.7948718,33.5897435 21.025641,34.1025641 20,34.1025641 Z M22.0512821,24.8717949 L1.02564105,24.8717949 C0.256410288,24.8717949 0,24.6153846 0,24.3589744 L0,0.512820504 C0,0.256410252 0.512820504,0 1.02564105,0 L38.974359,0 C39.7435897,0 40,0.256410252 40,0.512820504 L40,24.3589744 C40,24.6153846 39.4871795,24.8717949 38.974359,24.8717949 L22.0512821,24.8717949 Z M2.05128205,22.8205128 L37.9487179,22.8205128 L37.9487179,2.05128205 L2.05128205,2.05128205 L2.05128205,11.2820513 L36.6666666,11.2820513 L36.6666666,13.3333333 L2.05128205,13.3333333 L2.05128205,22.8205128 L2.05128205,22.8205128 Z M33.3333333,19.2307692 L33.3333333,17.1794872 L35.3846154,17.1794872 L35.3846154,19.2307692 L33.3333333,19.2307692 Z M33.3333333,7.69230771 L33.3333333,5.64102566 L35.3846154,5.64102566 L35.3846154,7.69230771 L33.3333333,7.69230771 Z"
id="形状"></path>
</svg>
<svg width="40" height="35" xmlns="http://www.w3.org/2000/svg"><path d="M20 34.103c-1.026 0-1.795-.513-2.308-1.282l-.256-.257H8.974c-.512 0-1.282-.513-1.282-1.282 0-.77.77-1.026 1.282-1.026h8.718c.257-.512.513-.769 1.026-1.025l.256-.257v-4.102H1.026C0 24.872 0 24.359 0 24.102V.513C0 .257.513 0 1.026 0h37.948C40 0 40 .513 40 .513v23.846c0 .256-.513.77-1.026.77H21.026v3.845l.256.257c.513.256.77.513 1.026 1.025l.256.257h8.718c.513 0 1.026.513 1.026 1.282 0 .77-.513 1.026-1.026 1.026h-8.974c-.513 1.025-1.282 1.282-2.308 1.282zM2.051 22.82H37.95V2.308L2.05 2.05v9.231h34.616v2.051H2.05v9.488zm31.282-3.334V17.18h2.052v2.308h-2.052zm0-11.538V5.64h2.052v2.308h-2.052z"/><path d="M20 34.103c-1.026 0-1.795-.513-2.308-1.282l-.256-.257H8.974c-.512 0-1.025-.513-1.025-1.026 0-.512.513-1.025 1.025-1.025h8.462l.256-.257c.257-.512.513-.769 1.026-1.025l.256-.257v-4.359h2.052v4.36l.256.256c.513.256.77.513 1.026 1.025l.256.257h8.718c.513 0 1.026.513 1.026 1.025 0 .513-.513 1.026-1.026 1.026h-8.718l-.256.257c-.513.769-1.282 1.282-2.308 1.282zm2.051-9.231H1.026c-.77 0-1.026-.257-1.026-.513V.513C0 .256.513 0 1.026 0h37.948C39.744 0 40 .256 40 .513v23.846c0 .256-.513.513-1.026.513H22.051zm-20-2.051H37.95V2.05H2.05v9.231h34.616v2.051H2.05v9.488zm31.282-3.59v-2.052h2.052v2.052h-2.052zm0-11.539V5.641h2.052v2.051h-2.052z"/></svg>

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -1,8 +1 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="40px" height="32px" viewBox="0 0 40 32" version="1.1" xmlns="http://www.w3.org/2000/svg"
>
<path d="M33.3333333,11.556 L24,11.556 C23.2636203,11.556 22.6666667,12.1529537 22.6666667,12.8893333 C22.6666667,13.625713 23.2636203,14.2226667 24,14.2226667 L33.3333333,14.2226667 C34.069713,14.2226667 34.6666667,13.625713 34.6666667,12.8893333 C34.6666667,12.1529537 34.069713,11.556 33.3333333,11.556 Z M33.3333333,18.2226667 L24,18.2226667 C23.2636203,18.2226667 22.6666667,18.8196203 22.6666667,19.556 C22.6666667,20.2923797 23.2636203,20.8893333 24,20.8893333 L33.3333333,20.8893333 C34.069713,20.8893333 34.6666667,20.2923797 34.6666667,19.556 C34.6666667,18.8196203 34.069713,18.2226667 33.3333333,18.2226667 Z M15.5146667,21.14 L15.5146667,20.2706667 C16.7986667,19.4386667 18.0373333,17.9773333 18.7133333,16.1853333 C19.192,15.9773333 19.536,15.3893333 19.8133333,14.3413333 C20.028,13.5293333 19.684,12.9933333 19.2186667,12.696 C18.9893333,8.868 16.756,6.66666667 13.3333333,6.66666667 C9.86266667,6.66666667 7.52266667,8.932 7.34266667,12.8613333 C6.92133333,13.2093333 6.65066667,13.768 6.86133333,14.564 C7.16133333,15.6986667 7.532,16.3506667 8.04266667,16.6 C8.764,18.2106667 9.94533333,19.5173333 11.152,20.2826667 L11.152,21.14 C7.79333333,21.5013333 5.33333333,22.6773333 5.33333333,24.072 C5.33333333,25.7546667 21.3333333,25.7546667 21.3333333,24.072 C21.3333333,22.6773333 18.8733333,21.5013333 15.5146667,21.14 L15.5146667,21.14 Z"
id="形状"></path>
<path d="M36,0 L4,0 C1.790861,0 0,1.790861 0,4 L0,28 C0,30.209139 1.790861,32 4,32 L36,32 C38.209139,32 40,30.209139 40,28 L40,4 C40,1.790861 38.209139,0 36,0 L36,0 Z M37.3333333,28 C37.3333333,28.7363797 36.7363797,29.3333333 36,29.3333333 L4,29.3333333 C3.26362033,29.3333333 2.66666667,28.7363797 2.66666667,28 L2.66666667,4 C2.66666667,3.26362033 3.26362033,2.66666667 4,2.66666667 L36,2.66666667 C36.7363797,2.66666667 37.3333333,3.26362033 37.3333333,4 L37.3333333,28 Z"
id="形状"></path>
</svg>
<svg width="40" height="32" xmlns="http://www.w3.org/2000/svg"><path d="M33.333 11.556H24a1.333 1.333 0 1 0 0 2.667h9.333a1.333 1.333 0 0 0 0-2.667zm0 6.667H24a1.333 1.333 0 1 0 0 2.666h9.333a1.333 1.333 0 1 0 0-2.666zM15.515 21.14v-.87c1.284-.831 2.522-2.293 3.198-4.085.479-.208.823-.796 1.1-1.844.215-.812-.129-1.348-.594-1.645-.23-3.828-2.463-6.03-5.886-6.03-3.47 0-5.81 2.266-5.99 6.195-.422.348-.692.907-.482 1.703.3 1.135.671 1.787 1.182 2.036.721 1.61 1.902 2.917 3.109 3.683v.857c-3.359.361-5.819 1.537-5.819 2.932 0 1.683 16 1.683 16 0 0-1.395-2.46-2.57-5.818-2.932z"/><path d="M36 0H4a4 4 0 0 0-4 4v24a4 4 0 0 0 4 4h32a4 4 0 0 0 4-4V4a4 4 0 0 0-4-4zm1.333 28c0 .736-.597 1.333-1.333 1.333H4A1.333 1.333 0 0 1 2.667 28V4c0-.736.597-1.333 1.333-1.333h32c.736 0 1.333.597 1.333 1.333v24z"/></svg>

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 804 B

View File

@@ -1,8 +1 @@
<svg width="43px" height="43px" viewBox="0 0 43 43" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path d="M30.8597157,40.331332 C25.7237184,40.331332 21.5453925,36.5185883 21.5453925,31.8319645 C21.5453925,27.1453408 25.7237184,23.3325971 30.8597157,23.3325971 C35.9957131,23.3325971 40.1740389,27.1453408 40.1740389,31.8319645 C40.1740389,36.5185882 35.995713,40.331332 30.8597157,40.331332 Z M30.8597157,26.5654481 C27.6722084,26.5654481 25.0882231,28.9233478 25.0882231,31.8319645 C25.0882231,34.7405812 27.6722084,37.0984809 30.8597157,37.0984809 C34.0472231,37.0984809 36.6312083,34.7405812 36.6312083,31.8319645 C36.6275476,28.9247326 34.0457056,26.5687885 30.8597157,26.5654481 Z M0.103517085,42.3109481 L0,5.67415866 L12.2321765,5.64536611 L12.2410335,8.87821712 L3.5522413,8.89842246 L3.6369371,39.0700149 L21.2857695,39.0280889 L21.2946265,42.2609399 L0.103517085,42.3109481 Z M39.2390638,23.03962 L39.199207,8.81457039 L30.5098612,8.83528082 L30.5010041,5.60242982 L42.732627,5.57363722 L42.7818944,23.0315379 L39.2390638,23.03962 L39.2390638,23.03962 Z"
id="形状"></path>
<polygon id="路径"
points="11.5158603 11.5569373 11.4915034 2.94997656 18.8212879 2.93280204 18.8306986 6.16565307 15.0431912 6.17424032 15.0492804 8.31549901 27.6982929 8.28569614 27.6922037 6.14443749 23.9417853 6.15352989 23.9329283 2.92067885 31.2261773 2.90350432 31.2505342 11.510465"></polygon>
<path d="M15.2457518,5.59939899 C15.2413867,4.1181016 15.8821393,2.69589808 17.0270489,1.64576232 C18.1719586,0.595626552 19.7272051,0.00361237818 21.3505368,0 L21.3665902,0 C24.7391532,0.00331652328 27.4746437,2.49314384 27.4868302,5.57060643 L23.9439996,5.57868856 C23.9385165,4.28263381 22.7863725,3.23423142 21.3660367,3.23285105 L21.3599475,3.23285105 C20.6763299,3.23432269 20.0213689,3.48360964 19.5392244,3.92584263 C19.0570799,4.36807563 18.78727,4.96700796 18.789181,5.59081175 L15.2457518,5.59939899 Z M9.46915602,16.2654838 L27.5584065,16.1876933 L27.5751242,19.4205444 L9.48587376,19.4983348 L9.46915602,16.2654838 Z M9.47762559,25.0359055 L17.8697057,25.0359055 L17.8697057,28.2687565 L9.47762559,28.2687565 L9.47762559,25.0359055 Z M34.6033252,37.740808 L37.0732317,35.4231569 L43,40.6822984 L40.5300381,43 L34.6033252,37.740808 Z"
id="形状"></path>
</svg>
<svg width="43" height="43" xmlns="http://www.w3.org/2000/svg"><path d="M30.86 40.331c-5.136 0-9.315-3.812-9.315-8.499 0-4.687 4.179-8.5 9.315-8.5 5.136 0 9.314 3.813 9.314 8.5 0 4.687-4.178 8.5-9.314 8.5zm0-13.766c-3.188 0-5.772 2.358-5.772 5.267 0 2.909 2.584 5.266 5.772 5.266 3.187 0 5.771-2.357 5.771-5.266-.003-2.907-2.585-5.263-5.771-5.267zM.104 42.311L0 5.674l12.232-.029.009 3.233-8.689.02.085 30.172 17.649-.042.009 3.233-21.191.05zM39.239 23.04L39.2 8.815l-8.69.02-.008-3.233 12.232-.028.049 17.458-3.543.008z"/><path d="M11.516 11.557l-.024-8.607 7.33-.017.009 3.233-3.788.008.006 2.141 12.65-.03-.007-2.14-3.75.009-.01-3.233 7.294-.017.025 8.606z"/><path d="M15.246 5.6c-.005-1.482.636-2.904 1.781-3.954C18.172.596 19.727.004 21.351 0h.016c3.372.003 6.108 2.493 6.12 5.57l-3.543.009c-.005-1.296-1.158-2.345-2.578-2.346h-.006a2.706 2.706 0 0 0-1.82.693 2.25 2.25 0 0 0-.75 1.665l-3.544.008zM9.469 16.264l18.09-.077.016 3.233-18.09.077-.016-3.233zm.009 8.77h8.392v3.234H9.478v-3.233zm25.125 12.706l2.47-2.318L43 40.683 40.53 43l-5.927-5.26z"/></svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -1,14 +1 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="40px" height="40px" viewBox="0 0 40 40" version="1.1" xmlns="http://www.w3.org/2000/svg"
>
<path d="M29.0073656,6.57920808 C28.985442,6.59193104 28.9632288,6.60414831 28.9407436,6.6158502 L25.8161706,8.42130713 C25.5100668,8.59806983 25.1462703,8.64595899 24.8048499,8.55443458 C24.4634295,8.46291018 24.1723673,8.23947333 23.9957237,7.93330076 L23.6626136,7.35702026 C23.4858509,7.05091645 23.4379617,6.68711997 23.5294861,6.34569959 C23.6210105,6.00427921 23.8444473,5.71321696 24.1506199,5.53657338 L24.9517498,5.0735503 C23.9843583,4.5620065 22.9639874,4.15765591 21.9087887,3.86769161 C18.123543,2.81393725 14.0734911,3.3277722 10.6713184,5.29340299 C3.60771804,9.3740021 1.2259806,18.492892 5.36653953,25.6664187 C5.82623152,26.4625519 2.94149776,28.1281025 2.48180582,27.3319693 C-2.57480599,18.5728384 0.339907639,7.41198343 9.00410218,2.40866923 C13.1781065,-0.00315109649 18.1466356,-0.635171047 22.7915306,0.654844387 C24.8534823,1.22113162 26.8055077,2.14717777 28.5543359,3.38801302 C28.9243431,3.46609837 29.2435702,3.69809836 29.4320811,4.02591891 L29.7651912,4.60219945 C29.9419539,4.90830326 29.989843,5.27209975 29.8983186,5.61352013 C29.8067942,5.95494051 29.5833574,6.24600276 29.2771848,6.42264634 L29.0073656,6.57920808 Z M6.40917427,32.4701931 C6.39645131,32.4482695 6.38423404,32.4260563 6.37253215,32.4035711 L6.20098042,32.1087686 C6.02421772,31.8026648 5.97632856,31.4388683 6.06785297,31.0974479 C6.15937737,30.7560276 6.38281422,30.4649653 6.68898679,30.2883217 L10.150001,28.2896609 C10.4561049,28.1128983 10.8199013,28.0650091 11.1613217,28.1565335 C11.5027421,28.2480579 11.7938044,28.4714947 11.9704479,28.7776673 L12.3035581,29.3539478 C12.4803208,29.6600516 12.5282099,30.0238481 12.4366855,30.3652685 C12.3451611,30.7066889 12.1217243,30.9977511 11.8155517,31.1743947 L10.9744486,31.6590699 C11.956063,32.1830806 12.9928388,32.5964502 14.0657106,32.8915774 C17.8511779,33.9448303 21.9012419,33.4303935 25.303181,31.4642005 C32.241865,27.4585512 34.6552479,18.5778351 30.8161537,11.4659337 C30.8007645,11.4369804 30.7852192,11.4081105 30.7695182,11.3793251 C30.6813515,11.2208655 30.7361318,11.0209917 30.892769,10.9296264 L33.2028877,9.59552035 C33.2832356,9.54935797 33.3791811,9.53875028 33.4676725,9.56624585 C33.556164,9.59374142 33.6292032,9.65685503 33.6692419,9.74042326 C38.4810178,18.4512532 35.5329931,29.4055799 26.9687316,34.3489343 C22.7951816,36.7602985 17.8273488,37.3923062 13.1829688,36.1027591 C11.077603,35.5243946 9.09226911,34.5751568 7.32023046,33.2996374 C6.98822653,33.2048121 6.70623453,32.9843565 6.53409057,32.6850492 L6.40917427,32.4685276 L6.40917427,32.4701931 Z"
id="形状"></path>
<path d="M16.2209332,19.6837607 L19.7519006,19.6837607 L18.0330523,14.7937039 L17.9964102,14.7937039 L16.2209332,19.6837607 Z M16.5074079,11.5092381 L19.5803489,11.5092381 L24.6769339,24.8336433 L21.5656853,24.8336433 L20.5330439,21.8656321 L15.4364588,21.8656321 L14.3705064,24.8336433 L11.3525286,24.8336433 L16.5074079,11.5092381 Z"
id="形状"></path>
<path d="M37.8347841,30.9528765 L38.0013392,30.9528765 C39.3337797,30.9528765 40,31.6190967 40,32.9515372 L40,33.0548014 C40,34.3872419 39.3337797,35.0534622 38.0013392,35.0534622 L37.8347841,35.0534622 C36.5023436,35.0534622 35.8361233,34.3872419 35.8361233,33.0548014 L35.8361233,32.9515372 C35.8361233,31.6190967 36.5023436,30.9528765 37.8347841,30.9528765 L37.8347841,30.9528765 Z"
id="路径"></path>
<path d="M29.5903084,30.9645353 L36.6988786,26.5891337 C36.9458872,26.4367653 37.2560706,26.4302273 37.5092801,26.5720524 C37.7624897,26.7138774 37.9189519,26.9817878 37.9180655,27.2720095 L37.9180655,38.7576469 C37.9177426,39.0472724 37.7608062,39.3140762 37.5078237,39.4550828 C37.2548411,39.5960895 36.9453796,39.5892452 36.6988786,39.4371915 L29.5903084,35.065121 L24.943422,35.065121 C24.0603581,35.065121 23.3444934,34.3492563 23.3444934,33.4661924 L23.3444934,32.5617984 C23.3444934,31.6790566 24.0606802,30.9628698 24.943422,30.9628698 L29.5903084,30.9628698 L29.5903084,30.9645353 Z"
id="路径"></path>
<path d="M26.4674009,35.065121 L29.2438738,35.065121 L29.2438738,38.3645769 C29.2438738,38.8061089 28.8859415,39.1640412 28.4444095,39.1640412 L27.2668652,39.1640412 C26.8253332,39.1640412 26.4674009,38.8061089 26.4674009,38.3645769 L26.4674009,35.065121 Z"
id="路径"></path>
</svg>
<svg width="40" height="40" xmlns="http://www.w3.org/2000/svg"><path d="M29.007 6.58a1.654 1.654 0 0 1-.066.036L25.816 8.42a1.332 1.332 0 0 1-1.82-.488l-.333-.576a1.332 1.332 0 0 1 .488-1.82l.8-.463a15.028 15.028 0 0 0-3.042-1.206A14.624 14.624 0 0 0 10.67 5.293c-7.063 4.081-9.445 13.2-5.304 20.373.46.797-2.426 2.462-2.885 1.666C-2.575 18.572.34 7.412 9.004 2.409A17.955 17.955 0 0 1 22.792.655a18.374 18.374 0 0 1 5.762 2.733c.37.078.69.31.878.638l.333.576a1.332 1.332 0 0 1-.488 1.82l-.27.157zM6.41 32.47a1.654 1.654 0 0 1-.036-.066l-.172-.295a1.332 1.332 0 0 1 .488-1.82l3.461-2a1.332 1.332 0 0 1 1.82.489l.334.576a1.332 1.332 0 0 1-.488 1.82l-.842.485c.982.524 2.019.937 3.092 1.233a14.624 14.624 0 0 0 11.237-1.428c6.939-4.005 9.352-12.886 5.513-19.998a9.108 9.108 0 0 0-.046-.087.333.333 0 0 1 .123-.45l2.31-1.333a.333.333 0 0 1 .466.144c4.812 8.711 1.864 19.666-6.7 24.609a17.955 17.955 0 0 1-13.786 1.754A18.361 18.361 0 0 1 7.32 33.3a1.327 1.327 0 0 1-.786-.615l-.125-.216v.001z"/><path d="M16.22 19.684h3.532l-1.719-4.89h-.037l-1.775 4.89zm.287-8.175h3.073l5.097 13.325h-3.111l-1.033-2.968h-5.097l-1.065 2.968h-3.018l5.154-13.325zM37.835 30.953H38c1.333 0 1.999.666 1.999 1.999v.103c0 1.332-.666 1.998-1.999 1.998h-.166c-1.333 0-1.999-.666-1.999-1.998v-.103c0-1.333.666-2 1.999-2z"/><path d="M29.59 30.965l7.109-4.376a.8.8 0 0 1 1.22.683v11.486a.8.8 0 0 1-1.22.68l-7.109-4.373h-4.647a1.599 1.599 0 0 1-1.599-1.599v-.904a1.6 1.6 0 0 1 1.6-1.6h4.646v.003z"/><path d="M26.467 35.065h2.777v3.3a.8.8 0 0 1-.8.799h-1.177a.8.8 0 0 1-.8-.8v-3.299z"/></svg>

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -1,8 +1 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="40px" height="40px" viewBox="0 0 40 40" version="1.1" xmlns="http://www.w3.org/2000/svg"
>
<path d="M27.5,7.5 L33.75,7.5 L33.75,10 L27.5,10 L27.5,7.5 Z M27.5,15 L33.75,15 L33.75,17.5 L27.5,17.5 L27.5,15 Z M27.5,22.5 L33.75,22.5 L33.75,25 L27.5,25 L27.5,22.5 Z M23.75,7.5 L1.25,7.5 C0.5625,7.5 0,8.0625 0,8.75 L0,38.75 C0,39.4375 0.5625,40 1.25,40 L23.75,40 C24.4375,40 25,39.4375 25,38.75 L25,8.75 C25,8.0625 24.4375,7.5 23.75,7.5 Z M22.5,37.5 L2.5,37.5 L2.5,10 L22.5,10 L22.5,37.5 Z"
id="形状"></path>
<path d="M6.25,15 L18.75,15 L18.75,17.5 L6.25,17.5 L6.25,15 Z M6.25,22.5 L18.75,22.5 L18.75,25 L6.25,25 L6.25,22.5 Z M6.2890625,30 L18.7890625,30 L18.7890625,32.5 L6.2890625,32.5 L6.2890625,30 Z M38.75,0 L16.25,0 C15.5625,0 15,0.5625 15,1.25 L15,5 L17.5,5 L17.5,2.5 L37.5,2.5 L37.5,30 L27.5,30 L27.5,32.5 L38.75,32.5 C39.4375,32.5 40,31.9375 40,31.25 L40,1.25 C40,0.5625 39.4375,0 38.75,0 Z"
id="形状"></path>
</svg>
<svg width="40" height="40" xmlns="http://www.w3.org/2000/svg"><path d="M27.5 7.5h6.25V10H27.5V7.5zm0 7.5h6.25v2.5H27.5V15zm0 7.5h6.25V25H27.5v-2.5zm-3.75-15H1.25C.562 7.5 0 8.063 0 8.75v30C0 39.438.563 40 1.25 40h22.5c.688 0 1.25-.563 1.25-1.25v-30c0-.688-.563-1.25-1.25-1.25zm-1.25 30h-20V10h20v27.5z"/><path d="M6.25 15h12.5v2.5H6.25V15zm0 7.5h12.5V25H6.25v-2.5zm.04 7.5h12.5v2.5H6.29V30zM38.75 0h-22.5C15.562 0 15 .563 15 1.25V5h2.5V2.5h20V30h-10v2.5h11.25c.688 0 1.25-.563 1.25-1.25v-30C40 .562 39.437 0 38.75 0z"/></svg>

Before

Width:  |  Height:  |  Size: 1003 B

After

Width:  |  Height:  |  Size: 526 B

View File

@@ -1,7 +1 @@
<svg t="1730795663037" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="53312" width="200" height="200">
<path d="M81.4592 150.4768c-44.544 0-80.6912 35.0208-80.6912 78.2848v712.704c0 43.2128 36.1472 78.2848 80.6912 78.2848h686.6432c44.5952 0 80.7424-35.072 80.7424-78.336v-71.8848h90.3168c44.544 0 80.6912-35.0208 80.6912-78.2848V78.5408c0-43.2128-36.1472-78.2848-80.6912-78.2848H252.416c-44.544 0-80.6912 35.072-80.6912 78.336v71.8848H81.4592zM848.896 800.3584V228.7616c0-43.264-36.1472-78.336-80.7424-78.336H243.0976V69.2736h710.144v731.136h-104.448zM72.0896 941.4656V219.648h705.4336v731.136H72.0896v-9.3184z"
fill="#333333" p-id="53313"></path>
<path d="M215.1936 716.8a35.1232 35.1232 0 0 0-35.6352 34.6112c0 19.1488 15.9232 34.6112 35.6352 34.6112h203.3664a35.1232 35.1232 0 0 0 35.6864-34.6112 35.1232 35.1232 0 0 0-35.6864-34.56H215.1936z m0-186.9824a35.1232 35.1232 0 0 0-35.6352 34.56c0 19.0976 15.9232 34.6112 35.6352 34.6112h389.4272a35.1232 35.1232 0 0 0 35.6352-34.6112 35.1232 35.1232 0 0 0-35.6352-34.56H215.1936z m0-180.224a35.1232 35.1232 0 0 0-35.6352 34.56c0 19.1488 15.9232 34.6112 35.6352 34.6112h389.4272a35.1232 35.1232 0 0 0 35.6352-34.6112 35.1232 35.1232 0 0 0-35.6352-34.56H215.1936z"
fill="#333333" p-id="53314"></path>
</svg>
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><path d="M81.46 150.477c-44.545 0-80.692 35.02-80.692 78.285v712.704c0 43.212 36.147 78.284 80.691 78.284h686.643c44.596 0 80.743-35.072 80.743-78.336V869.53h90.317c44.544 0 80.69-35.021 80.69-78.285V78.54c0-43.213-36.146-78.285-80.69-78.285H252.416c-44.544 0-80.691 35.072-80.691 78.336v71.885H81.459zm767.436 649.881V228.762c0-43.264-36.147-78.336-80.742-78.336H243.098V69.274h710.144V800.41H848.794zM72.09 941.466V219.648h705.433v731.136H72.09v-9.318z" fill="currentColor"/><path d="M215.194 716.8a35.123 35.123 0 0 0-35.636 34.611c0 19.149 15.924 34.611 35.636 34.611H418.56a35.123 35.123 0 0 0 35.686-34.61 35.123 35.123 0 0 0-35.686-34.56H215.194zm0-186.982a35.123 35.123 0 0 0-35.636 34.56c0 19.097 15.924 34.61 35.636 34.61H604.62a35.123 35.123 0 0 0 35.635-34.61 35.123 35.123 0 0 0-35.635-34.56H215.194zm0-180.224a35.123 35.123 0 0 0-35.636 34.56c0 19.148 15.924 34.61 35.636 34.61H604.62a35.123 35.123 0 0 0 35.635-34.61 35.123 35.123 0 0 0-35.635-34.56H215.194z" fill="currentColor"/></svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,6 +1 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="40px" height="40px" viewBox="0 0 40 40" version="1.1" xmlns="http://www.w3.org/2000/svg"
>
<path d="M14.1544772,17.9867221 L3.82792681,17.9867221 C1.71480767,17.9843424 0.00237964093,16.2719144 -1.49811495e-15,14.1587953 L-1.49811495e-15,3.83008582 C0.00118962327,1.71612359 1.71396558,0.00238159493 3.82792681,0 L14.1544772,0 C16.2692817,0.00119110387 17.983372,1.7152814 17.9845631,3.83008582 L17.9845631,14.1587953 C17.9821815,16.2727565 16.2684395,17.9855325 14.1544772,17.9867221 Z M4.43892697,13.5542721 L13.5499541,13.5542721 L13.5499541,4.43460895 L4.43244994,4.43460895 L4.43892697,13.5542721 Z M36.1720732,17.9867221 L25.8433637,17.9867221 C23.7302446,17.9843424 22.0178166,16.2719144 22.0154369,14.1587953 L22.0154369,3.83008582 C22.0178166,1.71696668 23.7302446,0.0045386521 25.8433637,0.00215901117 L36.1720732,0.00215901117 C38.2851923,0.0045386521 39.9976204,1.71696668 40,3.83008582 L40,14.1587953 C39.9976204,16.2719144 38.2851923,17.9843424 36.1720732,17.9867221 L36.1720732,17.9867221 Z M26.4565229,13.5542721 L35.5761861,13.5542721 L35.5761861,4.43460895 L26.4478869,4.43460895 L26.4565229,13.5542721 Z M14.1544772,40.002159 L3.82792681,40.002159 C1.71480767,39.9997794 0.00237964093,38.2873513 -1.49811495e-15,36.1742322 L-1.49811495e-15,25.8455228 C0.00237964093,23.7324036 1.71480767,22.0199756 3.82792681,22.0175959 L14.1544772,22.0175959 C16.2675964,22.0199756 17.9800244,23.7324036 17.9824041,25.8455228 L17.9824041,36.1742322 C17.9800244,38.2873513 16.2675964,39.9997794 14.1544772,40.002159 Z M4.43892697,35.5697091 L13.5499541,35.5697091 L13.5499541,26.4500459 L4.43244994,26.4500459 L4.43892697,35.5697091 Z M36.1720732,40.002159 L25.8433637,40.002159 C23.7302446,39.9997794 22.0178166,38.2873513 22.0154369,36.1742322 L22.0154369,25.8455228 C22.0178166,23.7324036 23.7302446,22.0199756 25.8433637,22.0175959 L36.1720732,22.0175959 C38.2851923,22.0199756 39.9976204,23.7324036 40,25.8455228 L40,36.1742322 C39.9976204,38.2873513 38.2851923,39.9997794 36.1720732,40.002159 L36.1720732,40.002159 Z M26.4565229,35.5697091 L35.5761861,35.5697091 L35.5761861,26.4500459 L26.4478869,26.4500459 L26.4565229,35.5697091 Z"
id="形状"></path>
</svg>
<svg width="40" height="40" xmlns="http://www.w3.org/2000/svg"><path d="M14.154 17.987H3.828A3.832 3.832 0 0 1 0 14.159V3.83A3.832 3.832 0 0 1 3.828 0h10.326a3.832 3.832 0 0 1 3.83 3.83V14.16a3.832 3.832 0 0 1-3.83 3.828zM4.44 13.554h9.111v-9.12H4.432l.007 9.12zm31.733 4.433H25.843a3.832 3.832 0 0 1-3.828-3.828V3.83A3.832 3.832 0 0 1 25.843.002h10.33A3.832 3.832 0 0 1 40 3.83V14.16a3.832 3.832 0 0 1-3.828 3.828zm-9.715-4.433h9.12v-9.12h-9.13l.01 9.12zM14.154 40.002H3.828A3.832 3.832 0 0 1 0 36.174V25.846a3.832 3.832 0 0 1 3.828-3.828h10.326a3.832 3.832 0 0 1 3.828 3.828v10.328a3.832 3.832 0 0 1-3.828 3.828zM4.44 35.57h9.111v-9.12H4.432l.007 9.12zm31.733 4.432H25.843a3.832 3.832 0 0 1-3.828-3.828V25.846a3.832 3.832 0 0 1 3.828-3.828h10.33A3.832 3.832 0 0 1 40 25.846v10.328a3.832 3.832 0 0 1-3.828 3.828zm-9.715-4.432h9.12v-9.12h-9.13l.01 9.12z"/></svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 862 B

View File

@@ -1,7 +1 @@
<svg t="1736134870052" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="30043" width="200" height="200">
<path d="M863.936 864.448v-304a48 48 0 0 1 96 0v345.6c0 30.08-24.32 54.4-54.4 54.4H118.528a54.4 54.4 0 0 1-54.4-54.4V118.592c0-30.08 24.32-54.4 54.4-54.4h344.96a48 48 0 1 1 0 96h-303.36v704.256h703.808z"
fill="#666666" p-id="30044"></path>
<path d="M422.4 669.44a48 48 0 0 1-67.904-67.904L870.848 85.184a48 48 0 1 1 67.84 67.84L422.4 669.44z"
fill="#666666" p-id="30045"></path>
</svg>
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><path d="M863.936 864.448v-304a48 48 0 0 1 96 0v345.6c0 30.08-24.32 54.4-54.4 54.4H118.528a54.4 54.4 0 0 1-54.4-54.4V118.592c0-30.08 24.32-54.4 54.4-54.4h344.96a48 48 0 1 1 0 96h-303.36v704.256h703.808z" fill="currentColor"/><path d="M422.4 669.44a48 48 0 0 1-67.904-67.904L870.848 85.184a48 48 0 1 1 67.84 67.84L422.4 669.44z" fill="currentColor"/></svg>

Before

Width:  |  Height:  |  Size: 567 B

After

Width:  |  Height:  |  Size: 457 B

View File

@@ -1,6 +1 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="44px" height="30px" viewBox="0 0 44 30" version="1.1" xmlns="http://www.w3.org/2000/svg"
>
<polyline id="路径" points="40 13.7142857 40 0 26.2857143 0"></polyline>
<polyline id="路径" points="0 25.1428571 11.8148571 10.8571429 23.0685714 17.7142857 40 0"></polyline>
</svg>
<svg width="44" height="30" xmlns="http://www.w3.org/2000/svg"><path d="M40 13.714V0H26.286"/><path d="M0 25.143l11.815-14.286 11.254 6.857L40 0"/></svg>

Before

Width:  |  Height:  |  Size: 337 B

After

Width:  |  Height:  |  Size: 153 B

View File

@@ -1,10 +1 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="162px" height="176px" viewBox="0 0 162 176" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>编组</title>
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="编组" fill="#2C2C2C" fill-rule="nonzero">
<path d="M145.273438,109.375 C142.304688,109.375 139.882812,111.796875 139.882812,114.765625 L139.882812,164.316406 L10.78125,164.316406 L10.78125,87.3046875 L91.1132813,87.3046875 C94.0820313,87.3046875 96.5039063,84.8828125 96.5039063,81.9140625 C96.5039063,78.9453125 94.0820313,76.5234375 91.1132813,76.5234375 L31.25,76.5234375 L31.25,50.4296875 C31.25,28.5742188 49.0234375,10.8007813 70.8984375,10.8007813 L78.90625,10.8007813 C100.761719,10.8007813 118.535156,28.5742188 118.535156,50.4296875 L118.535156,54.609375 L118.554688,54.609375 C118.730469,57.421875 121.074219,59.6484375 123.925781,59.6484375 C126.894531,59.6484375 129.316406,57.2460938 129.316406,54.2578125 C129.316406,54.1210938 129.316406,53.984375 129.296875,53.8476563 L129.296875,50.4101563 C129.296875,22.6757813 106.621094,0 78.8867188,0 L70.8789063,0 C43.1445313,0 20.46875,22.6757813 20.46875,50.4101563 L20.46875,76.5039063 L5.390625,76.5039063 C2.421875,76.5039063 0,78.9257812 0,81.8945313 L0,170 C0,172.96875 2.421875,175.390625 5.390625,175.390625 C6.03515625,175.390625 6.66015625,175.273438 7.24609375,175.058594 L143.417969,175.058594 C144.003906,175.273438 144.609375,175.390625 145.273438,175.390625 C148.242188,175.390625 150.664063,172.96875 150.664063,170 L150.664063,114.746094 C150.644531,111.796875 148.222656,109.375 145.273438,109.375 Z" id="路径"></path>
<path d="M159.648438,56.9335938 C157.558594,54.84375 154.121094,54.84375 152.03125,56.9335938 L76.8945312,132.050781 C74.8046875,134.140625 74.8046875,137.578125 76.8945312,139.667969 C78.984375,141.757813 82.421875,141.757813 84.5117188,139.667969 L159.628906,64.5507813 C161.738281,62.4414063 161.738281,59.0234375 159.648438,56.9335938 Z" id="路径"></path>
</g>
</g>
</svg>
<svg width="162" height="176" xmlns="http://www.w3.org/2000/svg"><g fill="currentColor" fill-rule="nonzero"><path d="M145.273 109.375a5.401 5.401 0 0 0-5.39 5.39v49.551H10.78V87.305h80.332a5.401 5.401 0 0 0 5.39-5.39 5.401 5.401 0 0 0-5.39-5.392H31.25V50.43c0-21.856 17.773-39.63 39.648-39.63h8.008c21.856 0 39.63 17.774 39.63 39.63v4.18h.019a5.385 5.385 0 0 0 10.761-.352c0-.137 0-.274-.02-.41V50.41c0-27.734-22.675-50.41-50.41-50.41H70.88c-27.734 0-50.41 22.676-50.41 50.41v26.094H5.39A5.401 5.401 0 0 0 0 81.894V170a5.401 5.401 0 0 0 5.39 5.39 5.38 5.38 0 0 0 1.856-.331h136.172a5.299 5.299 0 0 0 1.855.332 5.401 5.401 0 0 0 5.391-5.391v-55.254c-.02-2.95-2.441-5.371-5.39-5.371z"/><path d="M159.648 56.934c-2.09-2.09-5.527-2.09-7.617 0L76.895 132.05c-2.09 2.09-2.09 5.527 0 7.617s5.527 2.09 7.617 0l75.117-75.117c2.11-2.11 2.11-5.528.02-7.617z"/></g></svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 859 B

View File

@@ -1,6 +1 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="42px" height="41px" viewBox="0 0 42 41" version="1.1" xmlns="http://www.w3.org/2000/svg"
>
<path d="M40,26.6666667 C40,29.1212656 38.0101544,31.1111111 35.5555556,31.1111111 L8.88888889,31.1111111 L0,40 L0,4.44444444 C0,1.98984556 1.98984556,0 4.44444444,0 L35.5555556,0 C38.0101544,0 40,1.98984556 40,4.44444444 L40,26.6666667 Z"
id="路径"></path>
</svg>
<svg width="42" height="41" xmlns="http://www.w3.org/2000/svg"><path d="M40 26.667a4.444 4.444 0 0 1-4.444 4.444H8.889L0 40V4.444A4.444 4.444 0 0 1 4.444 0h31.112A4.444 4.444 0 0 1 40 4.444v22.223z"/></svg>

Before

Width:  |  Height:  |  Size: 423 B

After

Width:  |  Height:  |  Size: 206 B

View File

@@ -1,6 +1 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="40px" height="47px" viewBox="0 0 40 47" version="1.1" xmlns="http://www.w3.org/2000/svg"
>
<path d="M32.0665083,16.5795724 L26.6033254,16.5795724 L26.6033254,6.60332542 C26.6033254,2.94536817 23.6579572,0 20,0 C16.3420428,0 13.3966746,2.94536817 13.3966746,6.60332542 L13.3966746,16.5795724 L7.93349169,16.5795724 C3.56294537,16.5795724 0,20.1425178 0,24.5130641 L0,27.2684086 C0,29.7387173 2.04275534,31.7814727 4.51306413,31.7814727 L4.70308789,31.7814727 L2.32779097,37.4346793 C1.47268409,39.4299287 1.71021378,41.7102138 2.89786223,43.5629454 C4.08551069,45.368171 6.12826603,46.4608076 8.31353919,46.4608076 L31.5914489,46.4608076 C33.824228,46.4608076 35.8669834,45.368171 37.0546318,43.4679335 C38.2422803,41.6152019 38.432304,39.2874109 37.4821853,37.2921615 L34.9168646,31.7814727 L35.4869359,31.7814727 C37.9572447,31.7814727 40,29.7387173 40,27.2684086 L40,24.5130641 C40,20.0950119 36.4370546,16.5795724 32.0665083,16.5795724 L32.0665083,16.5795724 Z M17.1971496,6.60332542 C17.1971496,5.08313539 18.432304,3.80047506 20,3.80047506 C21.52019,3.80047506 22.8028504,5.03562945 22.8028504,6.60332542 L22.8028504,16.5795724 L17.1971496,16.5795724 L17.1971496,6.60332542 Z M33.7767221,41.4251781 C33.2541568,42.1852732 32.4465558,42.6603325 31.4964371,42.6603325 L8.21852732,42.6603325 C7.31591449,42.6603325 6.50831354,42.2327791 5.98574822,41.4726841 C5.4631829,40.7125891 5.41567696,39.8099762 5.74821853,38.9548694 L8.6935867,31.9714964 L9.26365796,31.9714964 L9.26365796,37.7672209 C9.26365796,38.8123515 10.1187648,39.6674584 11.1638955,39.6674584 C12.2090261,39.6674584 13.064133,38.8123515 13.064133,37.7672209 L13.064133,32.0665083 L13.064133,31.9714964 L14.9643705,31.9714964 L14.9643705,37.7672209 C14.9643705,38.8123515 15.8194774,39.6674584 16.8646081,39.6674584 C17.9097387,39.6674584 18.7648456,38.8123515 18.7648456,37.7672209 L18.7648456,32.0665083 L18.7648456,31.9239905 L20.6650831,31.9239905 L20.6650831,37.7672209 C20.6650831,38.8123515 21.52019,39.6674584 22.5653207,39.6674584 C23.6104513,39.6674584 24.4655582,38.8123515 24.4655582,37.7672209 L24.4655582,32.0665083 L24.4655582,31.8764846 L26.3657957,31.8764846 L26.3657957,37.7672209 C26.3657957,38.8123515 27.2209026,39.6674584 28.2660333,39.6674584 C29.3111639,39.6674584 30.1662708,38.8123515 30.1662708,37.7672209 L30.1662708,32.0665083 L30.1662708,31.8289786 L30.8313539,31.8289786 L34.0617577,38.9073634 C34.3467933,39.6674584 34.2992874,40.6175772 33.7767221,41.4251781 Z M36.1995249,27.2209026 C36.1995249,27.6009501 35.8669834,27.9334917 35.4869359,27.9334917 L4.51306413,27.9334917 C4.13301663,27.9334917 3.80047506,27.6009501 3.80047506,27.2209026 L3.80047506,24.4655582 C3.80047506,22.1852732 5.65320665,20.3325416 7.93349169,20.3325416 L32.0665083,20.3325416 C34.3467933,20.3325416 36.1995249,22.1852732 36.1995249,24.4655582 L36.1995249,27.2209026 Z"
id="形状"></path>
</svg>
<svg width="40" height="47" xmlns="http://www.w3.org/2000/svg"><path d="M32.067 16.58h-5.464V6.603A6.59 6.59 0 0 0 20 0a6.59 6.59 0 0 0-6.603 6.603v9.977H7.933C3.563 16.58 0 20.143 0 24.513v2.755c0 2.47 2.043 4.513 4.513 4.513h.19l-2.375 5.654c-.855 1.995-.618 4.275.57 6.128a6.484 6.484 0 0 0 5.416 2.898H31.59c2.233 0 4.276-1.093 5.464-2.993 1.187-1.853 1.377-4.18.427-6.176l-2.565-5.51h.57c2.47 0 4.513-2.043 4.513-4.514v-2.755a7.917 7.917 0 0 0-7.933-7.933zm-14.87-9.977A2.808 2.808 0 0 1 20 3.8a2.808 2.808 0 0 1 2.803 2.803v9.977h-5.606V6.603zm16.58 34.822c-.523.76-1.33 1.235-2.28 1.235H8.218c-.903 0-1.71-.427-2.233-1.187-.523-.76-.57-1.663-.238-2.518l2.946-6.984h.57v5.796c0 1.045.855 1.9 1.9 1.9s1.9-.855 1.9-1.9v-5.796h1.9v5.796c0 1.045.855 1.9 1.9 1.9 1.046 0 1.9-.855 1.9-1.9v-5.843h1.901v5.843c0 1.045.855 1.9 1.9 1.9s1.9-.855 1.9-1.9V31.877h1.9v5.89c0 1.045.856 1.9 1.901 1.9s1.9-.855 1.9-1.9V31.83h.665l3.23 7.078a2.83 2.83 0 0 1-.284 2.518zM36.2 27.221a.73.73 0 0 1-.713.712H4.513a.73.73 0 0 1-.713-.712v-2.755a4.136 4.136 0 0 1 4.133-4.133h24.134a4.136 4.136 0 0 1 4.133 4.133v2.755z"/></svg>

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,6 +1 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="40px" height="41px" viewBox="0 0 40 41" version="1.1" xmlns="http://www.w3.org/2000/svg"
>
<path d="M39.9793912,39.1019711 L37.2439048,23.3290535 L38.1677767,23.3290535 C38.9110031,23.3290535 39.5097134,22.7303433 39.5097134,21.9871168 L39.5097134,12.0774303 C39.5097134,11.3342039 38.9110031,10.7354936 38.1677767,10.7354936 L25.4709909,10.7354936 L25.4709909,1.3419367 C25.4709909,0.598710222 24.8722807,0 24.1290542,0 L15.8709822,0 C15.1277557,0 14.5290455,0.598710222 14.5290455,1.3419367 L14.5290455,10.7354936 L1.83225973,10.7354936 C1.08903325,10.7354936 0.490323027,11.3342039 0.490323027,12.0774303 L0.490323027,21.9871168 C0.490323027,22.7303433 1.08903325,23.3290535 1.83225973,23.3290535 L2.75613154,23.3290535 L0.0206451801,39.1019711 C0.00516129502,39.1793905 0,39.2568099 0,39.329068 C0,40.0722945 0.598710222,40.6710047 1.3419367,40.6710047 L38.6580997,40.6710047 C38.7355191,40.6710047 38.8129385,40.6658434 38.8851967,40.6503596 C39.6181006,40.5264885 40.1084236,39.8297136 39.9793912,39.1019711 Z M4.10322954,14.3484001 L18.141952,14.3484001 L18.141952,3.61290651 L21.8580844,3.61290651 L21.8580844,14.3484001 L35.8968068,14.3484001 L35.8968068,19.716147 L4.10322954,19.716147 L4.10322954,14.3484001 Z M28.2580902,37.0580982 L28.2580902,29.006478 C28.2580902,28.779381 28.0722836,28.5935744 27.8451866,28.5935744 L25.367765,28.5935744 C25.140668,28.5935744 24.9548614,28.779381 24.9548614,29.006478 L24.9548614,37.0580982 L15.045175,37.0580982 L15.045175,29.006478 C15.045175,28.779381 14.8593684,28.5935744 14.6322714,28.5935744 L12.1548498,28.5935744 C11.9277528,28.5935744 11.7419462,28.779381 11.7419462,29.006478 L11.7419462,37.0580982 L4.041294,37.0580982 L6.36903805,23.6387312 L33.625837,23.6387312 L35.9535811,37.0580982 L28.2580902,37.0580982 Z"
id="形状"></path>
</svg>
<svg width="40" height="41" xmlns="http://www.w3.org/2000/svg"><path d="M39.98 39.102l-2.736-15.773h.924a1.34 1.34 0 0 0 1.342-1.342v-9.91a1.34 1.34 0 0 0-1.342-1.342H25.47V1.342A1.34 1.34 0 0 0 24.129 0h-8.258a1.34 1.34 0 0 0-1.342 1.342v9.393H1.832A1.34 1.34 0 0 0 .49 12.077v9.91a1.34 1.34 0 0 0 1.342 1.342h.924L.021 39.102a1.34 1.34 0 0 0 1.321 1.569h37.316a1.336 1.336 0 0 0 1.321-1.569zM4.102 14.348h14.039V3.613h3.716v10.735h14.039v5.368H4.103v-5.368zm24.155 22.71v-8.052a.414.414 0 0 0-.413-.412h-2.477a.414.414 0 0 0-.413.412v8.052h-9.91v-8.052a.414.414 0 0 0-.413-.412h-2.477a.414.414 0 0 0-.413.412v8.052h-7.7l2.327-13.42h27.257l2.328 13.42h-7.696z"/></svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 669 B

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