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.
Files changed (44) hide show
  1. package/README.md +72 -8
  2. package/package.json +28 -27
  3. package/packages/components/index.js +2 -0
  4. package/packages/components/sh-code-editor/index.vue +187 -43
  5. package/packages/components/sh-code-editor/themes/dark.js +1 -1
  6. package/packages/components/sh-code-editor/themes/dracula.js +1 -1
  7. package/packages/components/sh-date/index.vue +13 -9
  8. package/packages/components/sh-form/form.vue +7 -49
  9. package/packages/components/sh-form/js/props.js +63 -24
  10. package/packages/components/sh-form/js/useForm.js +33 -67
  11. package/packages/components/sh-form/query.vue +2 -5
  12. package/packages/components/sh-header/index.vue +2 -1
  13. package/packages/components/sh-input/index.vue +193 -0
  14. package/packages/components/sh-modal/index.vue +7 -0
  15. package/packages/components/sh-split/index.vue +22 -25
  16. package/packages/components/sh-table/components/export-modal.vue +234 -0
  17. package/packages/components/sh-table/components/{importModal.vue → import-modal.vue} +130 -95
  18. package/packages/components/sh-table/grid.vue +16 -10
  19. package/packages/components/sh-table/js/props.js +23 -11
  20. package/packages/components/sh-table/js/tableMethods.js +103 -126
  21. package/packages/components/sh-table/js/useTable.js +331 -162
  22. package/packages/components/sh-table/table.vue +12 -10
  23. package/packages/components/sh-toolbar/index.vue +2 -2
  24. package/packages/components/sh-tree/components/table-tree.vue +60 -72
  25. package/packages/components/sh-tree/index.vue +47 -44
  26. package/packages/components/sh-tree/mixin/treeProps.js +8 -9
  27. package/packages/components/sh-upload/index.vue +1 -1
  28. package/packages/css/main.scss +2 -2
  29. package/packages/css/theme.scss +1 -0
  30. package/packages/other/sh-menu/index.vue +5 -7
  31. package/packages/vxeTable/css/index.scss +7 -12
  32. package/packages/vxeTable/index.js +92 -33
  33. package/packages/vxeTable/render/cell/vxe-render-input.vue +1 -1
  34. package/packages/vxeTable/render/cell/vxe-render-number.vue +2 -2
  35. package/packages/vxeTable/render/cell/{vxe-render-goption.vue → vxe-render-oparate.vue} +11 -36
  36. package/packages/vxeTable/render/cell/vxe-render-progress.vue +1 -1
  37. package/packages/vxeTable/render/cell/vxe-render-switch.vue +8 -2
  38. package/packages/vxeTable/render/cell/vxe-render-table.vue +10 -1
  39. package/packages/vxeTable/render/cell/vxe-render-tree.vue +1 -1
  40. package/packages/vxeTable/render/globalRenders.jsx +6 -15
  41. package/packages/vxeTable/render/header/vxe-header-money.vue +1 -1
  42. package/packages/vxeTable/render/mixin/cell-hooks.js +18 -7
  43. package/packages/vxeTable/render/utils/index.js +138 -0
  44. 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
- createApp(App).use(ShView).mount('#app')
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
- 1. 暂无文档,请参考示例或者组件api
64
- 2. 作者QQ:577754811
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.6",
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.23.10",
19
- "@codemirror/lang-javascript": "^6.1.9",
20
- "@codemirror/lang-json": "^6.0.1",
21
- "@codemirror/lang-sql": "^6.5.2",
22
- "@vxe-ui/plugin-export-pdf": "^4.2.4",
23
- "@vxe-ui/plugin-export-xlsx": "^4.3.0",
24
- "@vxe-ui/plugin-menu": "^4.1.0",
25
- "@vxe-ui/plugin-render-wangeditor": "^4.0.5",
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.32.2",
31
+ "core-js": "^3.48.0",
31
32
  "countup.js": "^2.9.0",
32
- "cron-parser": "^4.8.1",
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.10",
38
+ "lunar-typescript": "^1.8.6",
38
39
  "popper.js": "^1.16.1",
39
- "sh-tools": "^2.3.10",
40
+ "sh-tools": "^2.3.12",
40
41
  "vue": "^3.5.20",
41
42
  "vue-masonry": "^0.16.0",
42
- "vue-router": "^4.5.1",
43
- "vxe-pc-ui": "^4.11.24",
44
- "vxe-table": "^4.17.38"
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.9.0",
48
- "@typescript-eslint/parser": "^6.9.0",
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.8",
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.2",
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.3.0",
60
- "eslint-plugin-prettier": "^4.0.0",
61
- "eslint-plugin-vue": "^9.0.0",
62
- "prettier": "^2.4.1",
63
- "sass": "^1.32.7",
64
- "sass-loader": "^12.0.0",
65
- "typescript": "^5.2.2"
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, drawSelection, lineNumbers, EditorView } from '@codemirror/view'
11
+ import { keymap, placeholder, EditorView } from '@codemirror/view'
12
12
  import { Compartment, EditorState, StateEffect } from '@codemirror/state'
13
- import { defaultKeymap, indentWithTab, historyKeymap, history } from '@codemirror/commands'
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: 'javascript'
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: [String, Number],
124
+ type: String,
72
125
  default: '100%'
73
126
  },
74
127
  height: {
75
- type: [String, Number],
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
- const codeExtensions = computed(() => {
96
- const { mode, disabled, multipleSelection, indent, theme, tab, wrap, extensions } = props
97
- const defaultExtensions = [basicSetup, history(), drawSelection(), lineNumbers(), placeholder(props.placeholder), keymap.of([...defaultKeymap, ...historyKeymap])]
98
- if (['javascript', 'js'].includes(mode.toLowerCase())) {
99
- defaultExtensions.push(javascript())
100
- } else if (['mysql', 'sql'].includes(mode.toLowerCase())) {
101
- defaultExtensions.push(sql())
102
- } else if (['json'].includes(mode.toLowerCase())) {
103
- defaultExtensions.push(json())
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
- return [
106
- ...defaultExtensions,
107
- EditorView.updateListener.of(updateListener),
108
- EditorView.focusChangeEffect.of(focusListener),
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
- EditorState.allowMultipleSelections.of(multipleSelection),
111
- tabSize.of(EditorState.tabSize.of(indent)),
112
- theme && themes[theme] ? themes[theme] : undefined,
113
- tab ? keymap.of([indentWithTab]) : undefined,
114
- wrap ? EditorView.lineWrapping : undefined,
115
- ...extensions
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
- () => props.codeExtensions,
275
+ () => codeExtensions.value,
136
276
  value => {
137
- codeEditor?.dispatch({
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: codeExtensions.value
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 = async ({ state, changes, docChanged }) => {
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 = '#2c313a',
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 = '#2c313a',
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 defaultProps = {}
117
- let vxeProps = $vUtils.omit(props, (val, key) => {
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 = [`size--${vmConfig.value.size}`]
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;