vue2-client 1.14.83 → 1.14.85

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 (22) hide show
  1. package/.history/src/base-client/components/his/XShiftSchedule/XShiftSchedule_20250613095553.vue +242 -0
  2. package/.history/src/base-client/components/his/XShiftSchedule/XShiftSchedule_20250613095610.vue +242 -0
  3. package/.history/src/base-client/components/his/XShiftSchedule/XShiftSchedule_20250613095612.vue +242 -0
  4. package/.history/src/base-client/components/his/XShiftSchedule/XShiftSchedule_20250613100041.vue +251 -0
  5. package/.history/src/base-client/components/his/XShiftSchedule/XShiftSchedule_20250613100047.vue +251 -0
  6. package/.history/src/base-client/components/his/XShiftSchedule/XShiftSchedule_20250613100054.vue +250 -0
  7. package/.history/src/base-client/components/his/XShiftSchedule/XShiftSchedule_20250613100105.vue +250 -0
  8. package/.history/src/base-client/components/his/XShiftSchedule/XShiftSchedule_20250613100107.vue +250 -0
  9. package/.history/src/base-client/components/his/XShiftSchedule/XShiftSchedule_20250613100114.vue +250 -0
  10. package/package.json +1 -1
  11. package/src/base-client/components/common/XFormTable/XFormTable.vue +7 -0
  12. package/src/base-client/components/his/XQuestionnaire/XQuestionnaire.vue +20 -7
  13. package/src/base-client/components/his/XQuestionnaire/XQuestionnaireDemo.vue +10 -1
  14. package/src/base-client/components/his/XQuestionnaire/XQuestionnaireItem.vue +0 -3
  15. package/src/base-client/components/his/XShiftSchedule/XShiftSchedule.vue +49 -31
  16. package/src/base-client/components/layout/XPageView/RenderRow.vue +57 -31
  17. package/src/base-client/components/layout/XPageView/XErrorView.vue +14 -3
  18. package/src/base-client/components/layout/XPageView/XPageView.vue +138 -71
  19. package/src/base-client/components/layout/XPageView/index.js +1 -3
  20. package/src/base-client/components/layout/XPageView/index.md +65 -26
  21. package/src/pages/XPageViewExample/index.vue +41 -8
  22. package/src/router/async/router.map.js +1 -1
@@ -2,71 +2,89 @@
2
2
  import { getConfigByName } from '@vue2-client/services/api/common'
3
3
  import { reactive, ref, provide } from 'vue'
4
4
  import RenderRow from './RenderRow'
5
- import Exp500 from '@vue2-client/pages/exception/500.vue'
5
+ import XErrorView from '@vue2-client/base-client/components/layout/XPageView/XErrorView.vue'
6
6
 
7
+ // 页面布局配置
7
8
  const layout = ref(null)
8
9
 
9
- // 加载状态,0:加载中,1:已加载,2:出现错误
10
- const loaded = ref(0)
10
+ // 加载状态:0-加载中,1-已加载,2-出现错误
11
+ const loadingStatus = {
12
+ LOADING: 0,
13
+ LOADED: 1,
14
+ ERROR: 2
15
+ }
16
+ const loaded = ref(loadingStatus.LOADING)
11
17
 
12
- // 声明组件总数
18
+ // 组件计数
13
19
  const componentTotal = ref(0)
14
-
15
- // 注册组件总数
16
20
  const registerComponentTotal = ref(0)
17
21
 
18
- // 组件注册集
22
+ // 组件注册集合
19
23
  const componentRefMap = reactive({})
20
24
 
21
- // 通用参数
22
- const data = {
25
+ // 数据上下文
26
+ const dataContext = reactive({
23
27
  comps: componentRefMap,
24
28
  func: {
25
- getConfigByName: getConfigByName
29
+ getConfigByName
26
30
  }
27
- }
31
+ })
28
32
 
29
33
  /**
30
34
  * 初始化构建页面组件
31
- * @param params
32
35
  */
33
- function init (params) {
34
- const {
35
- configName,
36
- configValue,
37
- serviceName
38
- } = params
39
- loaded.value = 0
40
- const getConfigAfter = (res) => {
41
- if (res == null) {
42
- loaded.value = 2
36
+ const init = (params) => {
37
+ const { configName, configValue, serviceName } = params
38
+
39
+ // 重置状态
40
+ loaded.value = loadingStatus.LOADING
41
+ componentTotal.value = 0
42
+ registerComponentTotal.value = 0
43
+ Object.keys(componentRefMap).forEach(key => delete componentRefMap[key])
44
+
45
+ const processConfig = (config) => {
46
+ if (!config) {
47
+ loaded.value = loadingStatus.ERROR
43
48
  return
44
49
  }
45
- layout.value = res
46
- // 设置组件总量
50
+
51
+ layout.value = config
47
52
  setComponentTotal(layout.value.children)
48
- loaded.value = 1
53
+ loaded.value = loadingStatus.LOADED
49
54
  }
55
+
50
56
  if (configName) {
51
- getConfigByName(configName, serviceName, getConfigAfter)
57
+ getConfigByName(configName, serviceName, processConfig)
58
+ } else if (configValue) {
59
+ try {
60
+ const config = typeof configValue === 'string' ? JSON.parse(configValue) : configValue
61
+ processConfig(config)
62
+ } catch (error) {
63
+ console.error('配置解析错误:', error)
64
+ loaded.value = loadingStatus.ERROR
65
+ }
52
66
  } else {
53
- getConfigAfter(JSON.parse(configValue))
67
+ loaded.value = loadingStatus.ERROR
54
68
  }
55
69
  }
56
70
 
57
71
  /**
58
72
  * 注册组件
59
- * @param name 组件名称
60
- * @param vm 组件实例
61
73
  */
62
- function registerComponent (name, vm) {
74
+ const registerComponent = (name, vm) => {
75
+ if (!vm) return
76
+
63
77
  componentRefMap[name] = vm
64
- registerComponentTotal.value = registerComponentTotal.value + 1
65
- console.info(`总组件数量:${componentTotal.value},已注册数量:${registerComponentTotal.value}`)
78
+ registerComponentTotal.value++
79
+ console.debug(`总组件数量:${componentTotal.value},已注册数量:${registerComponentTotal.value}`)
80
+
66
81
  // 初始化页面
67
- initPage()
82
+ if (layout.value?.onMounted && registerComponentTotal.value === 1) {
83
+ initPage()
84
+ }
85
+
86
+ // 所有组件都已注册完成
68
87
  if (registerComponentTotal.value >= componentTotal.value) {
69
- // 注册事件
70
88
  registerEvents(layout.value.children)
71
89
  }
72
90
  }
@@ -75,26 +93,33 @@ provide('registerComponent', registerComponent)
75
93
  /**
76
94
  * 初始化页面
77
95
  */
78
- function initPage () {
79
- if (layout.value.onMounted) {
80
- // eslint-disable-next-line no-eval
81
- const onMountedFun = eval('(' + layout.value.onMounted + ')')
82
- onMountedFun(data)
96
+ const initPage = () => {
97
+ if (!layout.value?.onMounted) return
98
+
99
+ try {
100
+ // 使用 Function 构造函数替代 eval
101
+ // eslint-disable-next-line no-new-func
102
+ const onMountedFun = new Function('data', `return (${layout.value.onMounted})(data)`)
103
+ onMountedFun(dataContext)
104
+ } catch (error) {
105
+ console.error('页面初始化错误:', error)
83
106
  }
84
107
  }
85
108
 
86
109
  /**
87
110
  * 设置需要注册的组件总数
88
- * @param children 组件集合
89
111
  */
90
- function setComponentTotal (children) {
112
+ const setComponentTotal = (children) => {
113
+ if (!children?.length) return
114
+
91
115
  children.forEach((child) => {
92
116
  // 如果不是row类型,追加组件数量
93
117
  if (child.type !== 'row') {
94
- componentTotal.value = componentTotal.value + 1
118
+ componentTotal.value++
95
119
  }
120
+
96
121
  // 递归追加子组件数量
97
- if (child.children) {
122
+ if (child.children?.length) {
98
123
  setComponentTotal(child.children)
99
124
  }
100
125
  })
@@ -102,54 +127,96 @@ function setComponentTotal (children) {
102
127
 
103
128
  /**
104
129
  * 注册组件事件
105
- * @param children 组件集合
106
130
  */
107
- function registerEvents (children) {
131
+ const registerEvents = (children) => {
132
+ if (!children?.length) return
133
+
108
134
  children.forEach((child) => {
109
135
  // 如果有事件,注册它们
110
136
  if (child.event) {
111
137
  Object.entries(child.event).forEach(([eventName, handler]) => {
112
- // eslint-disable-next-line no-eval
113
- const eventHandler = eval('(' + handler + ')')
114
- const componentInstance = componentRefMap[child.id]
115
- if (componentInstance) {
116
- // 创建一个包装函数以传递额外参数
117
- const wrappedHandler = function (...args) {
118
- // 这里可以传递额外的参数,例如:
119
- eventHandler.call(componentInstance, ...args, data)
138
+ try {
139
+ // 使用 Function 构造函数替代 eval
140
+ // eslint-disable-next-line no-new-func
141
+ const eventHandler = new Function('...args', `return (${handler})(...args)`)
142
+ const componentInstance = componentRefMap[child.id]
143
+
144
+ if (componentInstance) {
145
+ componentInstance.$on(eventName, (...args) => {
146
+ eventHandler.call(componentInstance, ...args, dataContext)
147
+ })
120
148
  }
121
- componentInstance.$on(eventName, wrappedHandler)
149
+ } catch (error) {
150
+ console.error(`注册事件 ${eventName} 错误:`, error)
122
151
  }
123
152
  })
124
153
  }
125
154
 
126
155
  // 递归注册子组件的事件
127
- if (child.children) {
156
+ if (child.children?.length) {
128
157
  registerEvents(child.children)
129
158
  }
130
159
  })
131
160
  }
132
161
 
133
- defineExpose({
134
- init
135
- })
136
-
162
+ // 导出组件接口
163
+ defineExpose({ init })
137
164
  </script>
138
165
 
139
166
  <template>
140
- <div class="liuli_page">
141
- <div class="liuli_page_main" v-if="loaded === 1">
142
- <render-row
143
- v-for="row in layout.children"
144
- :key="row.id"
145
- :row="row"
146
- />
147
- </div>
148
- <div class="liuli_page_error" v-else-if="loaded === 2">
149
- <exp500></exp500>
150
- </div>
151
- </div>
167
+ <a-row
168
+ type="flex"
169
+ :gutter="layout?.gutter || 0"
170
+ :align="layout?.align || 'top'"
171
+ :justify="layout?.justify || 'start'"
172
+ class="liuli-page">
173
+ <template v-if="loaded === loadingStatus.LOADED">
174
+ <template v-if="layout.children?.length">
175
+ <a-col v-for="row in layout.children" :key="`page-col-${row.id}`">
176
+ <render-row :row="row"/>
177
+ </a-col>
178
+ </template>
179
+ <template v-else>
180
+ <div class="liuli-page__empty">
181
+ <a-empty description="无页面内容" />
182
+ </div>
183
+ </template>
184
+ </template>
185
+
186
+ <template v-else-if="loaded === loadingStatus.LOADING">
187
+ <div class="liuli-page__loading">
188
+ <a-spin tip="页面加载中..." />
189
+ </div>
190
+ </template>
191
+
192
+ <template v-else>
193
+ <div class="liuli-page__error">
194
+ <XErrorView />
195
+ </div>
196
+ </template>
197
+ </a-row>
152
198
  </template>
153
199
 
154
200
  <style scoped lang="less">
201
+ .liuli-page {
202
+ position: relative;
203
+ width: 100%;
204
+ height: 100%;
205
+
206
+ &__content {
207
+ min-height: 100px;
208
+ }
209
+
210
+ &__loading, &__error, &__empty {
211
+ display: flex;
212
+ width: 100%;
213
+ justify-content: center;
214
+ align-items: center;
215
+ min-height: 200px;
216
+ }
217
+
218
+ &__error {
219
+ width: 100%;
220
+ }
221
+ }
155
222
  </style>
@@ -1,3 +1 @@
1
- import XPageView from './XPageView'
2
-
3
- export default XPageView
1
+ export { default } from './XPageView'
@@ -1,38 +1,77 @@
1
1
  # XPageView
2
2
 
3
- JSON配置构建页面的根容器组件
3
+ 基于 JSON 配置动态构建页面的容器组件,具有高度的灵活性和可扩展性。
4
4
 
5
- 引用方式:
5
+ ## 使用方法
6
6
 
7
7
  ```vue
8
8
  <template>
9
- <x-page-view ref="xPageView"></x-page-view>
9
+ <x-page-view ref="pageView" />
10
10
  </template>
11
- <script>
12
- import XPageView from '@vue2-client/base-client/components/layout/XPageView'
13
-
14
- export default {
15
- components: {
16
- XPageView
17
- },
18
- mounted () {
19
- this.initView()
20
- },
21
- methods: {
22
- // 初始化组件
23
- initView () {
24
- this.$refs.xPageView.init({
25
- configName: 'templateTreeConfig',
26
- serviceName: 'af-his'
27
- })
28
- }
29
- }
30
- }
11
+
12
+ <script setup>
13
+ import { ref, onMounted } from 'vue'
14
+ import XPageView from '@vue2-client/base-client/components/layout/XPageView'
15
+
16
+ const pageView = ref(null)
17
+
18
+ onMounted(() => {
19
+ initView()
20
+ })
21
+
22
+ const initView = () => {
23
+ pageView.value.init({
24
+ configName: 'templateTreeConfig',
25
+ serviceName: 'af-his'
26
+ })
27
+ }
31
28
  </script>
32
29
  ```
33
30
 
34
31
  ## API
35
32
 
36
- | 参数 | 说明 | 类型 | 默认值 |
37
- |--------------|---------|----------|-----|
38
- | init(params) | 初始化组件 | function | - |
33
+ ### 属性
34
+
35
+ | 参数 | 说明 | 类型 | 默认值 |
36
+ | --- | --- | --- | --- |
37
+ | - | - | - | - |
38
+
39
+ ### 方法
40
+
41
+ | 方法名 | 说明 | 参数 |
42
+ | --- | --- | --- |
43
+ | init | 初始化页面组件 | `{ configName, configValue, serviceName }` |
44
+
45
+ ### 参数说明
46
+
47
+ | 参数名 | 说明 | 类型 | 必填 |
48
+ | --- | --- | --- | --- |
49
+ | configName | 配置名称,用于从服务端获取配置 | String | 二选一 |
50
+ | configValue | 配置的JSON数据,可以是字符串或对象 | String/Object | 二选一 |
51
+ | serviceName | 服务名称 | String | 是 |
52
+
53
+ ## 结构化配置项
54
+
55
+ ```json
56
+ {
57
+ "children": [
58
+ {
59
+ "type": "row",
60
+ "id": "row1",
61
+ "gutter": 16,
62
+ "children": [
63
+ {
64
+ "type": "XFormTable",
65
+ "id": "table1",
66
+ "span": 24,
67
+ "props": { ... },
68
+ "event": {
69
+ "change": "function(val, data) { console.log(val) }"
70
+ }
71
+ }
72
+ ]
73
+ }
74
+ ],
75
+ "onMounted": "function(data) { console.log('页面已加载') }"
76
+ }
77
+ ```
@@ -8,19 +8,52 @@ onMounted(() => {
8
8
  xPageViewRef.value.init({
9
9
  configValue: `{
10
10
  "type": "page",
11
- "onMounted": "function (data) {data.comps['xTreeView1'].init({configName: 'templateTreeConfig',serviceName: 'af-his',env: 'dev'})}",
11
+ "onMounted": "function (data) {}",
12
+ "gutter": [16, 16],
12
13
  "children": [
13
14
  {
14
- "id": "xTreeView1",
15
- "type": "XTreeView",
15
+ "id": "row1",
16
+ "type": "row",
17
+ "gutter": 16,
18
+ "children": [
19
+ {
20
+ "id": "xFormTable2",
21
+ "span": "12",
22
+ "type": "XFormTable",
23
+ "event": {
24
+ },
25
+ "props": {
26
+ "serviceName": "af-system",
27
+ "queryParamsName": "crud_dictionary_manage"
28
+ },
29
+ "children": [
30
+ ]
31
+ },
32
+ {
33
+ "id": "xFormTable3",
34
+ "span": "12",
35
+ "type": "XFormTable",
36
+ "event": {
37
+ },
38
+ "props": {
39
+ "serviceName": "af-system",
40
+ "queryParamsName": "crud_dictionary_manage"
41
+ },
42
+ "children": [
43
+ ]
44
+ }
45
+ ]
46
+ },
47
+ {
48
+ "id": "xFormTable",
49
+ "type": "XFormTable",
16
50
  "event": {
17
- "itemChecked": "function itemChecked (node, data) { if (node.type === 'all' || node.type === 'folder') { data.comps['xTreeViewAddNativeForm1'].close();return} data.func.getConfigByName('编辑模板数据Form', 'af-his', (res) => { data.comps['xTreeViewAddNativeForm1'].init({serviceName: 'af-his',formItems: res.formJson,showSubmitBtn: false,title: '收费',businessType: '新增',getDataParams: { content: {pms_patient_id: 1,template_id: node.id}}})})}"
51
+ },
52
+ "props": {
53
+ "serviceName": "af-system",
54
+ "queryParamsName": "crud_dictionary_manage"
18
55
  },
19
56
  "children": [
20
- {
21
- "id": "xTreeViewAddNativeForm1",
22
- "type": "XAddNativeForm"
23
- }
24
57
  ]
25
58
  }
26
59
  ]
@@ -66,7 +66,7 @@ routerResource.example = {
66
66
  // component: () => import('@vue2-client/base-client/components/common/XRate/demo.vue'),
67
67
  // component: () => import('@vue2-client/base-client/components/common/XForm/demo.vue'),
68
68
  // component: () => import('@vue2-client/base-client/components/his/XTimeSelect/XTimeSelectDemo.vue'),
69
- component: () => import('@vue2-client/base-client/components/his/XShiftSchedule/dome.vue'),
69
+ component: () => import('@vue2-client/base-client/components/his/XQuestionnaire/XQuestionnaireDemo.vue'),
70
70
  // component: () => import('@vue2-client/pages/WorkflowDetail/WorkFlowDemo.vue'),
71
71
  // component: () => import('@vue2-client/base-client/components/common/XConversation/XConversationDemo.vue'),
72
72
  // component: () => import('@vue2-client/base-client/components/common/XButtons/XButtonDemo.vue'),