sh-view 2.10.6 → 2.10.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +72 -8
- package/package.json +28 -27
- package/packages/components/index.js +2 -0
- package/packages/components/sh-code-editor/index.vue +187 -43
- package/packages/components/sh-code-editor/themes/dark.js +1 -1
- package/packages/components/sh-code-editor/themes/dracula.js +1 -1
- package/packages/components/sh-date/index.vue +13 -9
- package/packages/components/sh-form/form.vue +7 -49
- package/packages/components/sh-form/js/props.js +63 -24
- package/packages/components/sh-form/js/useForm.js +33 -67
- package/packages/components/sh-form/query.vue +2 -5
- package/packages/components/sh-header/index.vue +2 -1
- package/packages/components/sh-input/index.vue +193 -0
- package/packages/components/sh-modal/index.vue +7 -0
- package/packages/components/sh-split/index.vue +22 -25
- package/packages/components/sh-table/components/export-modal.vue +234 -0
- package/packages/components/sh-table/components/{importModal.vue → import-modal.vue} +130 -95
- package/packages/components/sh-table/grid.vue +16 -10
- package/packages/components/sh-table/js/props.js +23 -11
- package/packages/components/sh-table/js/tableMethods.js +103 -126
- package/packages/components/sh-table/js/useTable.js +331 -162
- package/packages/components/sh-table/table.vue +12 -10
- package/packages/components/sh-toolbar/index.vue +2 -2
- package/packages/components/sh-tree/components/table-tree.vue +60 -72
- package/packages/components/sh-tree/index.vue +47 -44
- package/packages/components/sh-tree/mixin/treeProps.js +8 -9
- package/packages/components/sh-upload/index.vue +1 -1
- package/packages/css/main.scss +2 -2
- package/packages/css/theme.scss +1 -0
- package/packages/other/sh-menu/index.vue +5 -7
- package/packages/vxeTable/css/index.scss +7 -12
- package/packages/vxeTable/index.js +92 -33
- package/packages/vxeTable/render/cell/vxe-render-input.vue +1 -1
- package/packages/vxeTable/render/cell/vxe-render-number.vue +2 -2
- package/packages/vxeTable/render/cell/{vxe-render-goption.vue → vxe-render-oparate.vue} +11 -36
- package/packages/vxeTable/render/cell/vxe-render-progress.vue +1 -1
- package/packages/vxeTable/render/cell/vxe-render-switch.vue +8 -2
- package/packages/vxeTable/render/cell/vxe-render-table.vue +10 -1
- package/packages/vxeTable/render/cell/vxe-render-tree.vue +1 -1
- package/packages/vxeTable/render/globalRenders.jsx +6 -15
- package/packages/vxeTable/render/header/vxe-header-money.vue +1 -1
- package/packages/vxeTable/render/mixin/cell-hooks.js +18 -7
- package/packages/vxeTable/render/utils/index.js +138 -0
- package/packages/components/sh-table/components/sh-column.vue +0 -68
package/README.md
CHANGED
|
@@ -54,20 +54,84 @@ npm install sh-tools sh-view@next
|
|
|
54
54
|
```javascript
|
|
55
55
|
import { createApp } from 'vue'
|
|
56
56
|
import ShView from 'sh-view'
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
// 进行全局自定义,可扩展性更强
|
|
58
|
+
let options = {
|
|
59
|
+
uiOption: {},
|
|
60
|
+
tableOption: {},
|
|
61
|
+
menuOption: {},
|
|
62
|
+
editorOption: {},
|
|
63
|
+
validateOption: {}
|
|
64
|
+
}
|
|
65
|
+
createApp(App).use(ShView, options).mount('#app')
|
|
59
66
|
```
|
|
60
67
|
|
|
61
68
|
#### 使用说明
|
|
69
|
+
1. table与form的二次封装完全保留的vxe-table的所有功能,在其基础上进行扩展
|
|
70
|
+
2. table与form支持了公式配置计算,并解决了公式互相依赖计算问题,全局配置如下
|
|
71
|
+
```javascript
|
|
72
|
+
// 以下为默认配置
|
|
73
|
+
// enabled 为false,则关闭公式计算
|
|
74
|
+
// data 为扩展参数计算的数据,例如一些计算要从系统的菜单或者用户信息中取数据使用,计算时会进行Object.assign({}, row, data),注意data中的信息会覆盖
|
|
75
|
+
// type 参数说明 all:实时全局计算,row: 整行计算,编辑后整行所有公式均计算,edit: 按需计算,编辑后所有依赖此字段的项进行重新计算
|
|
76
|
+
uiOption.caculateConfig = {
|
|
77
|
+
enabled: true,
|
|
78
|
+
type: 'edit',
|
|
79
|
+
data: {}
|
|
80
|
+
}
|
|
81
|
+
// 例如有 a b c d四个字段 存在公式 c = d * 2, a = b + c, 则会优先计算 c, 然后再进行计算 a = b + c得到正确的结果
|
|
82
|
+
// 示例表头配置
|
|
83
|
+
// 注意支持公式计算的只有 $vMoney 及 $vNumber渲染器
|
|
84
|
+
let columns = [
|
|
85
|
+
{ field: a, title: 'a', renderName: '$vMoney', renderPorps: { formula: '{b} + {c}' } },
|
|
86
|
+
{ field: b, title: 'b', renderName: '$vMoney' },
|
|
87
|
+
{ field: c, title: 'c', renderName: '$vMoney', renderPorps: { formula: '{d} * 2' } },
|
|
88
|
+
{ field: d, title: 'd', renderName: '$vMoney' },
|
|
89
|
+
]
|
|
90
|
+
// 更多公式计算配置 详见 sh-tools 内有详细说明
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
3. table支持了金额切换,全局配置如下
|
|
94
|
+
```javascript
|
|
95
|
+
// 以下为默认配置
|
|
96
|
+
// enabled 为false,则关闭金额
|
|
97
|
+
// titleUnit 渲染器为 $vMoney的表头 是否显示金额单位
|
|
98
|
+
// options 为金额切换下拉数据源
|
|
99
|
+
uiOption.moneyConfig = {
|
|
100
|
+
enabled: false,
|
|
101
|
+
titleUnit: true,
|
|
102
|
+
options: [
|
|
103
|
+
{ value: 1, label: '元', digits: 2 },
|
|
104
|
+
{ value: 1000, label: '千元', digits: 4 },
|
|
105
|
+
{ value: 10000, label: '万元', digits: 6 }
|
|
106
|
+
]
|
|
107
|
+
}
|
|
108
|
+
```
|
|
62
109
|
|
|
63
|
-
|
|
64
|
-
|
|
110
|
+
4. table的导入导出功能完善,完全进行重构,高级导出面板更使用于用户使用,扩展了导出是否在表头上增加金额单位,及自定义的表格ID,及表头信息,用于在导出的模板在导入时进行校验,支持了多级表头的导入导出
|
|
111
|
+
详见 userTable.js 中的onExportData方法
|
|
112
|
+
且导入导出方法中增加了事件钩子
|
|
113
|
+
如果导出全量数据时,要配置 getAllDataMethod去数据
|
|
114
|
+
导入时增加了 importBefore, importValidate, importFinished, downloadTemplate, downloadFinished等钩子用户自定义校验及处理数据
|
|
65
115
|
|
|
116
|
+
5. code编辑器组件,扩展了编码自动补全方案,
|
|
117
|
+
```javascript
|
|
118
|
+
// 以下为示例配置
|
|
119
|
+
// jsSnippets 为js模式扩展的自定义自动补全
|
|
120
|
+
// sqlSnippets 为sql模式扩展的自定义自动补全
|
|
121
|
+
// jsonSnippets 为json模式扩展的自定义自动补全
|
|
122
|
+
uiOption.codeConfig = {
|
|
123
|
+
jsSnippets: [
|
|
124
|
+
{ label: 'const', content: 'const ${}', detail: 'const' },
|
|
125
|
+
{ label: 'let', content: 'let ${}', detail: 'let' }
|
|
126
|
+
],
|
|
127
|
+
sqlSnippets: [
|
|
128
|
+
{ label: 'select', content: 'select ${}', detail: 'select' },
|
|
129
|
+
{ label: 'sf', content: 'select * from ${}', detail: 'select * from' }
|
|
130
|
+
],
|
|
131
|
+
jsonSnippets: []
|
|
132
|
+
}
|
|
133
|
+
```
|
|
66
134
|
|
|
67
|
-
#### 功能计划
|
|
68
|
-
* [x] v2.6.4 基于 vxe4.+,包含vxe-table所有功能,扩展更强渲染器
|
|
69
|
-
* [x] v2.6.7:独立日历组件,扩展日期选择组件(支持日期的单选,范围选择,多日期选择等);
|
|
70
|
-
* [ ] 下一阶段:基础sh-view的admin系统开源(包含低代码设计模板,及系统鉴权、路由守卫等)
|
|
71
135
|
|
|
72
136
|
|
|
73
137
|
#### 项目预览
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sh-view",
|
|
3
|
-
"version": "2.10.
|
|
3
|
+
"version": "2.10.8",
|
|
4
4
|
"description": "基于vxe-table二次封装,更包含Alert,Badge,Card,CodeEditor,Col,Corner,CountTo,Drawer,Empty,Form,Header,Icon,List,Loading,Modal,Noticebar,Poptip,Progress,PullRefresh,Query,Result,Row,Split,Grid,Table,Tabs,Tag,Toolbar,Tree,Upload,WaterFall,WaterMark等丰富组件库",
|
|
5
5
|
"main": "packages/index.js",
|
|
6
6
|
"typings": "types/index.d.ts",
|
|
@@ -15,53 +15,54 @@
|
|
|
15
15
|
"author": "神秘的sh",
|
|
16
16
|
"license": "ISC",
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@babel/eslint-parser": "^7.
|
|
19
|
-
"@codemirror/lang-javascript": "^6.
|
|
20
|
-
"@codemirror/lang-json": "^6.0.
|
|
21
|
-
"@codemirror/lang-sql": "^6.
|
|
22
|
-
"@vxe-ui/plugin-export-pdf": "^4.
|
|
23
|
-
"@vxe-ui/plugin-export-xlsx": "^4.
|
|
24
|
-
"@vxe-ui/plugin-menu": "^4.1
|
|
25
|
-
"@vxe-ui/plugin-render-wangeditor": "^4.
|
|
18
|
+
"@babel/eslint-parser": "^7.28.6",
|
|
19
|
+
"@codemirror/lang-javascript": "^6.2.4",
|
|
20
|
+
"@codemirror/lang-json": "^6.0.2",
|
|
21
|
+
"@codemirror/lang-sql": "^6.10.0",
|
|
22
|
+
"@vxe-ui/plugin-export-pdf": "^4.4.0",
|
|
23
|
+
"@vxe-ui/plugin-export-xlsx": "^4.5.1",
|
|
24
|
+
"@vxe-ui/plugin-menu": "^4.3.1",
|
|
25
|
+
"@vxe-ui/plugin-render-wangeditor": "^4.3.1",
|
|
26
|
+
"@vxe-ui/plugin-validator": "^4.3.1",
|
|
26
27
|
"@wangeditor/editor": "^5.1.23",
|
|
27
28
|
"@wolf-table/table": "^0.0.1",
|
|
28
29
|
"babel-polyfill": "^6.26.0",
|
|
29
30
|
"codemirror": "^6.0.2",
|
|
30
|
-
"core-js": "^3.
|
|
31
|
+
"core-js": "^3.48.0",
|
|
31
32
|
"countup.js": "^2.9.0",
|
|
32
|
-
"cron-parser": "^4.
|
|
33
|
+
"cron-parser": "^4.9.0",
|
|
33
34
|
"docx-preview": "^0.1.20",
|
|
34
35
|
"exceljs": "^4.4.0",
|
|
35
36
|
"jspdf": "^3.0.4",
|
|
36
37
|
"jszip": "^3.10.1",
|
|
37
|
-
"lunar-typescript": "^1.6
|
|
38
|
+
"lunar-typescript": "^1.8.6",
|
|
38
39
|
"popper.js": "^1.16.1",
|
|
39
|
-
"sh-tools": "^2.3.
|
|
40
|
+
"sh-tools": "^2.3.12",
|
|
40
41
|
"vue": "^3.5.20",
|
|
41
42
|
"vue-masonry": "^0.16.0",
|
|
42
|
-
"vue-router": "^4.
|
|
43
|
-
"vxe-pc-ui": "^4.
|
|
44
|
-
"vxe-table": "^4.17.
|
|
43
|
+
"vue-router": "^4.6.4",
|
|
44
|
+
"vxe-pc-ui": "^4.12.30",
|
|
45
|
+
"vxe-table": "^4.17.48"
|
|
45
46
|
},
|
|
46
47
|
"devDependencies": {
|
|
47
|
-
"@typescript-eslint/eslint-plugin": "^6.
|
|
48
|
-
"@typescript-eslint/parser": "^6.
|
|
48
|
+
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
|
49
|
+
"@typescript-eslint/parser": "^6.21.0",
|
|
49
50
|
"@vue/cli-plugin-babel": "~5.0.8",
|
|
50
51
|
"@vue/cli-plugin-eslint": "~5.0.8",
|
|
51
52
|
"@vue/cli-plugin-router": "~5.0.8",
|
|
52
|
-
"@vue/cli-plugin-typescript": "^5.0.
|
|
53
|
+
"@vue/cli-plugin-typescript": "^5.0.9",
|
|
53
54
|
"@vue/cli-plugin-vuex": "~5.0.8",
|
|
54
55
|
"@vue/cli-service": "~5.0.8",
|
|
55
56
|
"@vue/eslint-config-typescript": "^12.0.0",
|
|
56
|
-
"babel-loader": "^9.1
|
|
57
|
+
"babel-loader": "^9.2.1",
|
|
57
58
|
"compression-webpack-plugin": "~6.1.1",
|
|
58
59
|
"eslint": "^7.32.0",
|
|
59
|
-
"eslint-config-prettier": "^8.
|
|
60
|
-
"eslint-plugin-prettier": "^4.
|
|
61
|
-
"eslint-plugin-vue": "^9.
|
|
62
|
-
"prettier": "^2.
|
|
63
|
-
"sass": "^1.
|
|
64
|
-
"sass-loader": "^12.
|
|
65
|
-
"typescript": "^5.
|
|
60
|
+
"eslint-config-prettier": "^8.10.2",
|
|
61
|
+
"eslint-plugin-prettier": "^4.2.5",
|
|
62
|
+
"eslint-plugin-vue": "^9.33.0",
|
|
63
|
+
"prettier": "^2.8.8",
|
|
64
|
+
"sass": "^1.97.3",
|
|
65
|
+
"sass-loader": "^12.6.0",
|
|
66
|
+
"typescript": "^5.9.3"
|
|
66
67
|
}
|
|
67
68
|
}
|
|
@@ -13,6 +13,7 @@ import ShEmpty from './sh-empty/index.vue'
|
|
|
13
13
|
import ShForm from './sh-form/form.vue'
|
|
14
14
|
import ShHeader from './sh-header/index.vue'
|
|
15
15
|
import ShIcon from './sh-icon/index.vue'
|
|
16
|
+
import ShInput from './sh-input/index.vue'
|
|
16
17
|
import ShList from './sh-list/index.vue'
|
|
17
18
|
import ShLoading from './sh-loading/index.vue'
|
|
18
19
|
import ShModal from './sh-modal/index.vue'
|
|
@@ -50,6 +51,7 @@ const components = {
|
|
|
50
51
|
ShForm,
|
|
51
52
|
ShHeader,
|
|
52
53
|
ShIcon,
|
|
54
|
+
ShInput,
|
|
53
55
|
ShList,
|
|
54
56
|
ShLoading,
|
|
55
57
|
ShModal,
|
|
@@ -6,16 +6,68 @@
|
|
|
6
6
|
</template>
|
|
7
7
|
|
|
8
8
|
<script>
|
|
9
|
-
import { defineComponent, ref, computed, watch, onMounted, onUnmounted, nextTick } from 'vue'
|
|
9
|
+
import { defineComponent, ref, computed, watch, onMounted, onUnmounted, nextTick, getCurrentInstance } from 'vue'
|
|
10
10
|
import { basicSetup } from 'codemirror'
|
|
11
|
-
import { keymap, placeholder,
|
|
11
|
+
import { keymap, placeholder, EditorView } from '@codemirror/view'
|
|
12
12
|
import { Compartment, EditorState, StateEffect } from '@codemirror/state'
|
|
13
|
-
import { defaultKeymap, indentWithTab, historyKeymap
|
|
13
|
+
import { defaultKeymap, indentWithTab, historyKeymap } from '@codemirror/commands'
|
|
14
|
+
import { autocompletion, snippetCompletion, acceptCompletion } from '@codemirror/autocomplete'
|
|
15
|
+
import { closeBrackets, closeBracketsKeymap } from '@codemirror/autocomplete'
|
|
14
16
|
import themes from './themes'
|
|
15
17
|
import { javascript } from '@codemirror/lang-javascript'
|
|
16
18
|
import { sql } from '@codemirror/lang-sql'
|
|
17
19
|
import { json } from '@codemirror/lang-json'
|
|
18
20
|
const tabSize = new Compartment()
|
|
21
|
+
const completionConfig = new Compartment()
|
|
22
|
+
|
|
23
|
+
const jsDefaultSnippets = [
|
|
24
|
+
{ label: 'if', content: 'if (${}) {\n\t${}\n}', detail: 'if语句' },
|
|
25
|
+
{ label: 'else', content: 'else {\n\t${}\n}', detail: 'else语句' },
|
|
26
|
+
{ label: 'function', content: 'function ${}(${}) {\n\t${}\n}', detail: '函数定义' },
|
|
27
|
+
{ label: 'const', content: 'const ${}', detail: 'const' },
|
|
28
|
+
{ label: 'let', content: 'let ${}', detail: 'let' },
|
|
29
|
+
{ label: 'var', content: 'var ${}', detail: 'var' },
|
|
30
|
+
{ label: 'for', content: 'for ${}', detail: 'for' },
|
|
31
|
+
{ label: 'async', content: 'async ${}', detail: 'async' },
|
|
32
|
+
{ label: 'await', content: 'await ${}', detail: 'await' },
|
|
33
|
+
{ label: 'try', content: 'try ${}', detail: 'try' },
|
|
34
|
+
{ label: 'catch', content: 'catch ${}', detail: 'catch' },
|
|
35
|
+
{ label: 'finally', content: 'finally ${}', detail: 'finally' },
|
|
36
|
+
{ label: 'trycf', content: 'try {\n\t${}\n} catch(e) {} finally {}', detail: 'try catch' },
|
|
37
|
+
{ label: 'return', content: 'return', detail: 'return' },
|
|
38
|
+
{ label: 'ife', content: 'if (${}) {\n\t${}\n} else {\n\t${}\n}', detail: 'if else语句' }
|
|
39
|
+
]
|
|
40
|
+
const sqlDefaultSnippets = [
|
|
41
|
+
{ label: 'select', content: 'select ${}', detail: 'select' },
|
|
42
|
+
{ label: 'from', content: 'from ${}', detail: 'from' },
|
|
43
|
+
{ label: 'where', content: 'where ${}', detail: 'where' },
|
|
44
|
+
{ label: 'insert', content: 'insert ${}', detail: 'insert' },
|
|
45
|
+
{ label: 'update', content: 'update ${}', detail: 'update' },
|
|
46
|
+
{ label: 'delete', content: 'delete ${}', detail: 'delete' },
|
|
47
|
+
{ label: 'create', content: 'create ${}', detail: 'create' },
|
|
48
|
+
{ label: 'drop', content: 'drop ${}', detail: 'drop' },
|
|
49
|
+
{ label: 'join', content: 'join ${}', detail: 'join' },
|
|
50
|
+
{ label: 'left', content: 'left ${}', detail: 'left' },
|
|
51
|
+
{ label: 'right', content: 'right ${}', detail: 'right' },
|
|
52
|
+
{ label: 'on', content: 'on ${}', detail: 'on' },
|
|
53
|
+
{ label: 'group by', content: 'group by', detail: 'group by' },
|
|
54
|
+
{ label: 'order by', content: 'order by', detail: 'order by' },
|
|
55
|
+
{ label: 'having', content: 'having ${}', detail: 'having' },
|
|
56
|
+
{ label: 'limit', content: 'limit ${}', detail: 'limit' },
|
|
57
|
+
{ label: 'distinct', content: 'distinct ${}', detail: 'distinct' },
|
|
58
|
+
{ label: 'union', content: 'union ${}', detail: 'union' },
|
|
59
|
+
{ label: 'all', content: 'all ${}', detail: 'all' },
|
|
60
|
+
{ label: 'as', content: 'as ${}', detail: 'as' },
|
|
61
|
+
{ label: 'between', content: 'between ${}', detail: 'between' },
|
|
62
|
+
{ label: 'in', content: 'in ${}', detail: 'in' },
|
|
63
|
+
{ label: 'like', content: 'like ${}', detail: 'like' },
|
|
64
|
+
{ label: 'sf', content: 'select * from ${}', detail: 'select * from' },
|
|
65
|
+
{ label: 'lj', content: 'left join ${}', detail: 'left join' },
|
|
66
|
+
{ label: 'rj', content: 'right join ${}', detail: 'right join' },
|
|
67
|
+
{ label: 'rj', content: 'right join ${}', detail: 'right join' },
|
|
68
|
+
{ label: 'una', content: 'union all ${}', detail: 'union all' }
|
|
69
|
+
]
|
|
70
|
+
|
|
19
71
|
export default defineComponent({
|
|
20
72
|
name: 'ShCodeEditor',
|
|
21
73
|
props: {
|
|
@@ -31,7 +83,7 @@ export default defineComponent({
|
|
|
31
83
|
},
|
|
32
84
|
mode: {
|
|
33
85
|
type: String,
|
|
34
|
-
default: '
|
|
86
|
+
default: 'js' // js, sql, json
|
|
35
87
|
},
|
|
36
88
|
theme: {
|
|
37
89
|
type: String,
|
|
@@ -55,7 +107,8 @@ export default defineComponent({
|
|
|
55
107
|
type: Boolean
|
|
56
108
|
},
|
|
57
109
|
tab: {
|
|
58
|
-
type: Boolean
|
|
110
|
+
type: Boolean,
|
|
111
|
+
default: true
|
|
59
112
|
},
|
|
60
113
|
multipleSelection: {
|
|
61
114
|
type: Boolean,
|
|
@@ -68,20 +121,30 @@ export default defineComponent({
|
|
|
68
121
|
}
|
|
69
122
|
},
|
|
70
123
|
width: {
|
|
71
|
-
type:
|
|
124
|
+
type: String,
|
|
72
125
|
default: '100%'
|
|
73
126
|
},
|
|
74
127
|
height: {
|
|
75
|
-
type:
|
|
128
|
+
type: String,
|
|
76
129
|
default: 'auto'
|
|
130
|
+
},
|
|
131
|
+
autocomplete: {
|
|
132
|
+
type: Boolean,
|
|
133
|
+
default: false
|
|
134
|
+
},
|
|
135
|
+
autoclose: {
|
|
136
|
+
type: Boolean,
|
|
137
|
+
default: true
|
|
77
138
|
}
|
|
78
139
|
},
|
|
79
|
-
emits: ['update:modelValue', 'change', 'loaded', 'focus', 'blur', 'destroy'],
|
|
140
|
+
emits: ['update:modelValue', 'input', 'change', 'loaded', 'focus', 'blur', 'destroy'],
|
|
80
141
|
setup(props, context) {
|
|
142
|
+
const { proxy } = getCurrentInstance()
|
|
143
|
+
const { $vUtils, $vUiSetup } = proxy
|
|
81
144
|
const { emit } = context
|
|
82
145
|
|
|
83
|
-
let codeEditor = null
|
|
84
146
|
let codeLength = 0
|
|
147
|
+
const codeEditor = ref(null)
|
|
85
148
|
const codeError = ref(null)
|
|
86
149
|
const codeRef = ref()
|
|
87
150
|
|
|
@@ -92,39 +155,116 @@ export default defineComponent({
|
|
|
92
155
|
border: props.border ? '1px solid var(--border-color)' : 'none'
|
|
93
156
|
}
|
|
94
157
|
})
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
158
|
+
// 自定义Tab键行为:当补全菜单打开时,Tab选择补全;否则缩进
|
|
159
|
+
const customKeymap = () => {
|
|
160
|
+
let customList = [
|
|
161
|
+
{
|
|
162
|
+
key: 'Tab',
|
|
163
|
+
run: view => {
|
|
164
|
+
if (acceptCompletion(view)) {
|
|
165
|
+
return true
|
|
166
|
+
}
|
|
167
|
+
return false
|
|
168
|
+
},
|
|
169
|
+
preventDefault: true
|
|
170
|
+
}
|
|
171
|
+
]
|
|
172
|
+
if (props.tab) {
|
|
173
|
+
customList.push(indentWithTab)
|
|
174
|
+
}
|
|
175
|
+
return keymap.of([...customList, ...defaultKeymap, ...historyKeymap, ...closeBracketsKeymap])
|
|
176
|
+
}
|
|
177
|
+
// 自定义自动不全方案
|
|
178
|
+
const customCompletion = context => {
|
|
179
|
+
let codeConfig = $vUiSetup.codeConfig || {}
|
|
180
|
+
let snippets = []
|
|
181
|
+
let snippetList = []
|
|
182
|
+
if (props.mode === 'js') {
|
|
183
|
+
snippetList = jsDefaultSnippets.concat(codeConfig.jsSnippets)
|
|
184
|
+
} else if (props.mode === 'sql') {
|
|
185
|
+
snippetList = sqlDefaultSnippets.concat(codeConfig.sqlSnippets)
|
|
186
|
+
} else if (props.mode === 'json') {
|
|
187
|
+
snippetList = codeConfig.jsonSnippets
|
|
104
188
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
189
|
+
snippets = snippetList.map(item => snippetCompletion(item.content, Object.assign({ type: 'snippet', boost: 3 }, item)))
|
|
190
|
+
// 根据当前输入进行过滤
|
|
191
|
+
const word = context.matchBefore(/\w*/)
|
|
192
|
+
if (!word || (word.from === word.to && !context.explicit)) return null
|
|
193
|
+
// 过滤并返回结果
|
|
194
|
+
let wordLower = word.text.toLowerCase()
|
|
195
|
+
const filteredOptions = snippets
|
|
196
|
+
.filter(option => option.label.toLowerCase().includes(wordLower))
|
|
197
|
+
.toSorted((a, b) => {
|
|
198
|
+
const aLabel = a.label.toLowerCase()
|
|
199
|
+
const bLabel = b.label.toLowerCase()
|
|
200
|
+
const aStartsWith = aLabel.startsWith(wordLower)
|
|
201
|
+
const bStartsWith = bLabel.startsWith(wordLower)
|
|
202
|
+
if (aStartsWith && !bStartsWith) return -1
|
|
203
|
+
if (!aStartsWith && bStartsWith) return 1
|
|
204
|
+
if (aStartsWith && bStartsWith) {
|
|
205
|
+
if (aLabel.length !== bLabel.length) {
|
|
206
|
+
return aLabel.length - bLabel.length
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return aLabel.localeCompare(bLabel)
|
|
210
|
+
})
|
|
211
|
+
return {
|
|
212
|
+
from: word.from,
|
|
213
|
+
options: filteredOptions,
|
|
214
|
+
filter: false
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
const modeExtensions = computed(() => {
|
|
218
|
+
let resultExtensions = []
|
|
219
|
+
if (props.mode === 'js') {
|
|
220
|
+
resultExtensions.push(javascript())
|
|
221
|
+
} else if (props.mode === 'sql') {
|
|
222
|
+
resultExtensions.push(sql())
|
|
223
|
+
} else if (props.mode === 'json') {
|
|
224
|
+
resultExtensions.push(json())
|
|
225
|
+
}
|
|
226
|
+
if (props.autocomplete) {
|
|
227
|
+
resultExtensions.push(
|
|
228
|
+
completionConfig.of(
|
|
229
|
+
autocompletion({
|
|
230
|
+
override: [customCompletion],
|
|
231
|
+
activateOnTyping: true,
|
|
232
|
+
defaultKeymap: true,
|
|
233
|
+
closeOnBlur: true,
|
|
234
|
+
maxRenderedOptions: 20
|
|
235
|
+
})
|
|
236
|
+
)
|
|
237
|
+
)
|
|
238
|
+
}
|
|
239
|
+
return resultExtensions
|
|
240
|
+
})
|
|
241
|
+
|
|
242
|
+
const codeExtensions = computed(() => {
|
|
243
|
+
const { disabled, theme, wrap, autoclose, extensions } = props
|
|
244
|
+
const innerExtensions = [
|
|
245
|
+
basicSetup,
|
|
246
|
+
placeholder(props.placeholder),
|
|
247
|
+
tabSize.of(EditorState.tabSize.of(props.indent)),
|
|
248
|
+
EditorState.allowMultipleSelections.of(props.multipleSelection),
|
|
109
249
|
EditorView.editable.of(!disabled),
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
].filter(item => !!item)
|
|
250
|
+
customKeymap()
|
|
251
|
+
]
|
|
252
|
+
// 括号自动补全
|
|
253
|
+
if (autoclose) innerExtensions.push(closeBrackets())
|
|
254
|
+
if (theme && themes[theme]) innerExtensions.push(themes[theme])
|
|
255
|
+
if (wrap) innerExtensions.push(EditorView.lineWrapping)
|
|
256
|
+
return [...innerExtensions, ...modeExtensions.value, ...extensions].filter(item => !!item)
|
|
117
257
|
})
|
|
118
258
|
|
|
119
259
|
watch(
|
|
120
260
|
() => props.modelValue,
|
|
121
261
|
value => {
|
|
122
|
-
if (codeEditor && !codeEditor.composing) {
|
|
123
|
-
const docLength = codeEditor.state.doc.length
|
|
262
|
+
if (codeEditor.value && !codeEditor.value.composing) {
|
|
263
|
+
const docLength = codeEditor.value.state.doc.length
|
|
124
264
|
const docValue = getTransformValue(value)
|
|
125
|
-
codeEditor.dispatch({
|
|
265
|
+
codeEditor.value.dispatch({
|
|
126
266
|
changes: { from: 0, to: docLength, insert: docValue },
|
|
127
|
-
selection: codeEditor.state.selection,
|
|
267
|
+
selection: codeEditor.value.state.selection,
|
|
128
268
|
scrollIntoView: true
|
|
129
269
|
})
|
|
130
270
|
codeLength = docLength
|
|
@@ -132,24 +272,23 @@ export default defineComponent({
|
|
|
132
272
|
}
|
|
133
273
|
)
|
|
134
274
|
watch(
|
|
135
|
-
() =>
|
|
275
|
+
() => codeExtensions.value,
|
|
136
276
|
value => {
|
|
137
|
-
codeEditor
|
|
277
|
+
if (!codeEditor.value) return
|
|
278
|
+
codeEditor.value?.dispatch({
|
|
138
279
|
effects: StateEffect.reconfigure.of(value)
|
|
139
280
|
})
|
|
140
|
-
},
|
|
141
|
-
{
|
|
142
|
-
immediate: true
|
|
143
281
|
}
|
|
144
282
|
)
|
|
145
283
|
|
|
146
284
|
const codeRender = async () => {
|
|
147
285
|
const docValue = getTransformValue(props.modelValue)
|
|
286
|
+
let editExtensions = [EditorView.focusChangeEffect.of(focusListener), EditorView.updateListener.of(updateListener)].concat(codeExtensions.value)
|
|
148
287
|
const codeState = EditorState.create({
|
|
149
288
|
doc: docValue,
|
|
150
|
-
extensions:
|
|
289
|
+
extensions: editExtensions
|
|
151
290
|
})
|
|
152
|
-
codeEditor = new EditorView({
|
|
291
|
+
codeEditor.value = new EditorView({
|
|
153
292
|
parent: codeRef.value,
|
|
154
293
|
state: codeState
|
|
155
294
|
})
|
|
@@ -167,14 +306,14 @@ export default defineComponent({
|
|
|
167
306
|
}
|
|
168
307
|
}
|
|
169
308
|
|
|
170
|
-
const updateListener =
|
|
309
|
+
const updateListener = ({ state, changes, docChanged }) => {
|
|
171
310
|
if (changes.empty || !docChanged) return
|
|
172
311
|
const valueStr = state.doc.toString()
|
|
173
312
|
dispatchEvent('change', valueStr)
|
|
174
313
|
}
|
|
175
314
|
|
|
176
315
|
const focus = () => {
|
|
177
|
-
codeEditor && codeEditor.focus()
|
|
316
|
+
codeEditor.value && codeEditor.value.focus()
|
|
178
317
|
}
|
|
179
318
|
|
|
180
319
|
const getTransformValue = (value, out) => {
|
|
@@ -198,6 +337,7 @@ export default defineComponent({
|
|
|
198
337
|
const outValue = getTransformValue(value, true)
|
|
199
338
|
if (codeError.value) return
|
|
200
339
|
emit('update:modelValue', outValue)
|
|
340
|
+
emit('input', outValue)
|
|
201
341
|
}
|
|
202
342
|
|
|
203
343
|
const dispatchEvent = (type, value) => {
|
|
@@ -213,7 +353,7 @@ export default defineComponent({
|
|
|
213
353
|
codeRender()
|
|
214
354
|
})
|
|
215
355
|
onUnmounted(() => {
|
|
216
|
-
if (codeEditor) codeEditor.destroy()
|
|
356
|
+
if (codeEditor.value) codeEditor.value.destroy()
|
|
217
357
|
dispatchEvent('destroy', props.modelValue)
|
|
218
358
|
})
|
|
219
359
|
|
|
@@ -235,6 +375,10 @@ export default defineComponent({
|
|
|
235
375
|
.sh-code-content {
|
|
236
376
|
flex: 1;
|
|
237
377
|
display: block;
|
|
378
|
+
:deep(.cm-editor) {
|
|
379
|
+
height: 100%;
|
|
380
|
+
overflow: auto;
|
|
381
|
+
}
|
|
238
382
|
}
|
|
239
383
|
.sh-code-error {
|
|
240
384
|
position: absolute;
|
|
@@ -13,7 +13,7 @@ const chalky = '#e5c07b',
|
|
|
13
13
|
whiskey = '#d19a66',
|
|
14
14
|
violet = '#c678dd',
|
|
15
15
|
darkBackground = '#21252b',
|
|
16
|
-
highlightBackground = '#
|
|
16
|
+
highlightBackground = '#494a4c',
|
|
17
17
|
background = '#282c34',
|
|
18
18
|
tooltipBackground = '#353a42',
|
|
19
19
|
selection = '#3E4451',
|
|
@@ -13,7 +13,7 @@ const chalky = '#bd93f9',
|
|
|
13
13
|
whiskey = '#d19a66',
|
|
14
14
|
violet = '#c678dd',
|
|
15
15
|
darkBackground = '#21252b',
|
|
16
|
-
highlightBackground = '#
|
|
16
|
+
highlightBackground = '#494a4c',
|
|
17
17
|
background = '#282a36',
|
|
18
18
|
tooltipBackground = '#353a42',
|
|
19
19
|
selection = '#3E4451',
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<input class="vxe-input vxe-input--inner" v-bind="startInputConfig" />
|
|
8
8
|
<span>{{ separator }}</span>
|
|
9
9
|
<input class="vxe-input vxe-input--inner" v-bind="endInputConfig" />
|
|
10
|
-
<span class="sh-date-range-suffix sh-date-clear" @click.stop="onRangeClear"><i class="vxe-icon-error-circle-fill"></i></span>
|
|
10
|
+
<span v-if="!disabled && !readonly" class="sh-date-range-suffix sh-date-clear" @click.stop="onRangeClear"><i class="vxe-icon-error-circle-fill"></i></span>
|
|
11
11
|
<span class="sh-date-range-suffix"><i class="vxe-icon-calendar"></i></span>
|
|
12
12
|
</div>
|
|
13
13
|
</template>
|
|
@@ -113,12 +113,8 @@ export default defineComponent({
|
|
|
113
113
|
|
|
114
114
|
const vmConfig = computed(() => ({ size: props.size || $vUiSetup.size }))
|
|
115
115
|
const inputConfig = computed(() => {
|
|
116
|
-
let
|
|
117
|
-
|
|
118
|
-
return omitProps.includes(key) || $vUtils.isNone(val)
|
|
119
|
-
})
|
|
120
|
-
let shProps = {}
|
|
121
|
-
return Object.assign(defaultProps, vxeProps, shProps, vmConfig.value)
|
|
116
|
+
let vxeProps = $vUtils.omit(props, (val, key) => omitProps.includes(key) || $vUtils.isNone(val))
|
|
117
|
+
return Object.assign({}, vxeProps, vmConfig.value)
|
|
122
118
|
})
|
|
123
119
|
const pulldownConfig = computed(() => {
|
|
124
120
|
return Object.assign({ transfer: true }, props.pulldown, vmConfig.value)
|
|
@@ -129,9 +125,12 @@ export default defineComponent({
|
|
|
129
125
|
return props.format || 'yyyy-MM-dd'
|
|
130
126
|
})
|
|
131
127
|
const rangeInputConfig = computed(() => {
|
|
132
|
-
let returnConfig = { type: 'text', readonly: true }
|
|
128
|
+
let returnConfig = { type: 'text', readonly: true, class: [] }
|
|
133
129
|
if (vmConfig.value.size) {
|
|
134
|
-
returnConfig.class
|
|
130
|
+
returnConfig.class.push(`size--${vmConfig.value.size}`)
|
|
131
|
+
}
|
|
132
|
+
if (props.disabled) {
|
|
133
|
+
returnConfig.class.push(`is--disabled`)
|
|
135
134
|
}
|
|
136
135
|
return returnConfig
|
|
137
136
|
})
|
|
@@ -180,6 +179,7 @@ export default defineComponent({
|
|
|
180
179
|
})
|
|
181
180
|
|
|
182
181
|
const onRangeFocus = async e => {
|
|
182
|
+
if (props.disabled || props.readonly) return
|
|
183
183
|
pulldownValue.value = !pulldownValue.value
|
|
184
184
|
if (pulldownValue.value) {
|
|
185
185
|
dispatch('focus', e)
|
|
@@ -238,6 +238,7 @@ export default defineComponent({
|
|
|
238
238
|
pulldownValue,
|
|
239
239
|
inputValue,
|
|
240
240
|
rangeValue,
|
|
241
|
+
vmConfig,
|
|
241
242
|
inputConfig,
|
|
242
243
|
pulldownConfig,
|
|
243
244
|
startInputConfig,
|
|
@@ -255,6 +256,9 @@ export default defineComponent({
|
|
|
255
256
|
</script>
|
|
256
257
|
|
|
257
258
|
<style scoped lang="scss">
|
|
259
|
+
.vxe-form--item.is--error .sh-date-range-input {
|
|
260
|
+
border-color: var(--vxe-ui-form-validate-error-color);
|
|
261
|
+
}
|
|
258
262
|
.sh-date {
|
|
259
263
|
display: inline-flex;
|
|
260
264
|
position: relative;
|