vue2-client 1.18.39 → 1.18.40

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 (102) hide show
  1. package/.eslintrc.js +90 -90
  2. package/Components.md +60 -60
  3. package/docs/index.md +30 -30
  4. package/docs//350/257/267/346/261/202/345/267/245/345/205/267/344/275/277/347/224/250/350/257/264/346/230/216.md +353 -0
  5. package/index.js +31 -31
  6. package/jest-transform-stub.js +8 -8
  7. package/jest.setup.js +7 -7
  8. package/package.json +1 -1
  9. package/src/assets/img/querySlotDemo.svg +15 -15
  10. package/src/base-client/components/common/AmapMarker/AmapPointRendering.vue +120 -120
  11. package/src/base-client/components/common/CitySelect/index.js +3 -3
  12. package/src/base-client/components/common/CitySelect/index.md +109 -109
  13. package/src/base-client/components/common/CreateQuery/CreateQuery.vue +669 -669
  14. package/src/base-client/components/common/CreateQuery/index.js +3 -3
  15. package/src/base-client/components/common/CreateQuery/index.md +42 -42
  16. package/src/base-client/components/common/CreateSimpleFormQuery/index.js +3 -3
  17. package/src/base-client/components/common/CreateSimpleFormQuery/index.md +42 -42
  18. package/src/base-client/components/common/FormGroupEdit/index.js +3 -3
  19. package/src/base-client/components/common/FormGroupEdit/index.md +43 -43
  20. package/src/base-client/components/common/FormGroupQuery/FormGroupQuery.vue +166 -166
  21. package/src/base-client/components/common/FormGroupQuery/index.js +3 -3
  22. package/src/base-client/components/common/FormGroupQuery/index.md +43 -43
  23. package/src/base-client/components/common/JSONToTree/jsontotree.vue +271 -271
  24. package/src/base-client/components/common/PersonSetting/PersonSetting.vue +208 -208
  25. package/src/base-client/components/common/PersonSetting/index.js +3 -3
  26. package/src/base-client/components/common/Tree/Tree.vue +149 -149
  27. package/src/base-client/components/common/Tree/index.js +2 -2
  28. package/src/base-client/components/common/Upload/index.js +3 -3
  29. package/src/base-client/components/common/XAddNativeForm/index.md +146 -146
  30. package/src/base-client/components/common/XCard/XCard.vue +64 -64
  31. package/src/base-client/components/common/XDataDrawer/XDataDrawer.vue +180 -180
  32. package/src/base-client/components/common/XDataDrawer/index.js +3 -3
  33. package/src/base-client/components/common/XDataDrawer/index.md +41 -41
  34. package/src/base-client/components/common/XDescriptions/index.js +3 -3
  35. package/src/base-client/components/common/XDescriptions/index.md +322 -322
  36. package/src/base-client/components/common/XForm/index.md +178 -178
  37. package/src/base-client/components/common/XFormTable/demo.vue +2 -4
  38. package/src/base-client/components/common/XReport/print.js +186 -186
  39. package/src/base-client/components/common/XReportGrid/XReportTrGroup.vue +1 -1
  40. package/src/base-client/components/common/XStepView/XStepView.vue +252 -252
  41. package/src/base-client/components/common/XStepView/index.js +3 -3
  42. package/src/base-client/components/common/XStepView/index.md +31 -31
  43. package/src/base-client/components/common/XTable/XTable.vue +1715 -1715
  44. package/src/base-client/components/common/XTable/XTableWrapper.vue +786 -769
  45. package/src/base-client/components/common/XTable/index.md +255 -255
  46. package/src/base-client/components/system/DictionaryDetailsView/DictionaryDetailsView.vue +232 -232
  47. package/src/base-client/plugins/Config.js +19 -19
  48. package/src/base-client/plugins/tabs-page-plugin.js +39 -39
  49. package/src/components/Charts/Bar.vue +62 -62
  50. package/src/components/Charts/ChartCard.vue +134 -134
  51. package/src/components/Charts/Liquid.vue +67 -67
  52. package/src/components/Charts/MiniArea.vue +39 -39
  53. package/src/components/Charts/MiniBar.vue +39 -39
  54. package/src/components/Charts/MiniProgress.vue +75 -75
  55. package/src/components/Charts/MiniSmoothArea.vue +40 -40
  56. package/src/components/Charts/Radar.vue +68 -68
  57. package/src/components/Charts/RankList.vue +77 -77
  58. package/src/components/Charts/TagCloud.vue +113 -113
  59. package/src/components/Charts/TransferBar.vue +64 -64
  60. package/src/components/Charts/Trend.vue +82 -82
  61. package/src/components/Charts/chart.less +12 -12
  62. package/src/components/Charts/smooth.area.less +13 -13
  63. package/src/components/NumberInfo/NumberInfo.vue +54 -54
  64. package/src/components/NumberInfo/index.js +3 -3
  65. package/src/components/NumberInfo/index.less +54 -54
  66. package/src/components/NumberInfo/index.md +43 -43
  67. package/src/components/card/ChartCard.vue +79 -79
  68. package/src/components/chart/Bar.vue +60 -60
  69. package/src/components/chart/MiniArea.vue +67 -67
  70. package/src/components/chart/MiniBar.vue +59 -59
  71. package/src/components/chart/MiniProgress.vue +57 -57
  72. package/src/components/chart/Radar.vue +80 -80
  73. package/src/components/chart/RankingList.vue +60 -60
  74. package/src/components/chart/Trend.vue +79 -79
  75. package/src/components/chart/index.less +9 -9
  76. package/src/components/checkbox/ColorCheckbox.vue +157 -157
  77. package/src/components/input/IInput.vue +66 -66
  78. package/src/components/menu/SideMenu.vue +75 -75
  79. package/src/components/menu/menu.js +273 -273
  80. package/src/components/tool/AStepItem.vue +60 -60
  81. package/src/composables/demo/UseRequestDemo.vue +175 -0
  82. package/src/composables/index.js +6 -0
  83. package/src/composables/useGlobalLoading.js +206 -0
  84. package/src/composables/usePost.js +221 -0
  85. package/src/layouts/CommonLayout.vue +56 -56
  86. package/src/layouts/header/HeaderNotice.vue +177 -177
  87. package/src/lib.js +1 -1
  88. package/src/mock/extend/index.js +84 -84
  89. package/src/mock/goods/index.js +108 -108
  90. package/src/pages/dashboard/workplace/WorkPlace.vue +141 -141
  91. package/src/pages/system/dictionary/index.vue +44 -44
  92. package/src/pages/system/monitor/loginInfor/index.vue +37 -37
  93. package/src/pages/system/monitor/operLog/index.vue +37 -37
  94. package/src/services/api/cas.js +79 -79
  95. package/src/services/api/restTools.js +34 -46
  96. package/src/store/modules/setting.js +119 -119
  97. package/src/utils/authority-utils.js +85 -85
  98. package/src/utils/errorCode.js +6 -6
  99. package/src/utils/map-utils.js +47 -47
  100. package/src/utils/request.js +103 -0
  101. package/vue.config.js +9 -4
  102. package//350/277/201/347/247/273/346/227/245/345/277/227.md +15 -15
@@ -0,0 +1,175 @@
1
+ <template>
2
+ <a-card title="useRunLogic / usePost 请求工具示例" :bordered="false">
3
+ <a-space direction="vertical" style="width: 100%">
4
+ <!-- 示例1: 基础用法 - 组件级 loading -->
5
+ <a-button
6
+ type="primary"
7
+ :loading="basicRequest.loading"
8
+ @click="handleBasicRequest"
9
+ >
10
+ 基础请求 (组件级 loading)
11
+ </a-button>
12
+
13
+ <!-- 示例2: 全局 Loading -->
14
+ <a-button
15
+ type="danger"
16
+ :loading="globalLoadingRequest.loading"
17
+ @click="handleGlobalLoadingRequest"
18
+ >
19
+ 全局 Loading 请求
20
+ </a-button>
21
+
22
+ <!-- 示例3: 请求去重 -->
23
+ <a-button
24
+ type="dashed"
25
+ @click="handleDedupeRequest"
26
+ >
27
+ 去重请求 (快速点击试试)
28
+ </a-button>
29
+
30
+ <!-- 示例4: 组合使用 -->
31
+ <a-button
32
+ :loading="comboRequest.loading"
33
+ @click="handleComboRequest"
34
+ >
35
+ 组合使用 (去重 + 全局 Loading)
36
+ </a-button>
37
+
38
+ <!-- 示例5: usePost 基础用法 -->
39
+ <a-button
40
+ type="primary"
41
+ ghost
42
+ :loading="postRequest.loading"
43
+ @click="handlePostRequest"
44
+ >
45
+ usePost 示例
46
+ </a-button>
47
+
48
+ <!-- 显示请求结果 -->
49
+ <a-card v-if="requestResult" size="small" title="请求结果">
50
+ <pre style="margin: 0; font-size: 12px; max-height: 200px; overflow: auto;">{{ JSON.stringify(requestResult, null, 2) }}</pre>
51
+ </a-card>
52
+ </a-space>
53
+ </a-card>
54
+ </template>
55
+
56
+ <script>
57
+ import { useRunLogic, usePost } from '@vue2-client/composables'
58
+
59
+ export default {
60
+ name: 'UseRequestDemo',
61
+
62
+ data () {
63
+ return {
64
+ // 请求结果展示
65
+ requestResult: null,
66
+
67
+ // ========== useRunLogic 实例 ==========
68
+ // 示例1: 基础用法
69
+ basicRequest: useRunLogic('test'),
70
+
71
+ // 示例2: 全局 Loading
72
+ globalLoadingRequest: useRunLogic('test', {
73
+ globalLoading: '正在加载数据...'
74
+ }),
75
+
76
+ // 示例3: 请求去重
77
+ dedupeRequest: useRunLogic('test', {
78
+ dedupe: true
79
+ }),
80
+
81
+ // 示例4: 组合使用
82
+ comboRequest: useRunLogic('test', {
83
+ dedupe: true,
84
+ globalLoading: '处理中,请勿重复操作...'
85
+ }),
86
+
87
+ // ========== usePost 实例 ==========
88
+ postRequest: usePost('/api/af-safecheck/logic/test', {
89
+ globalLoading: '请求中...'
90
+ })
91
+ }
92
+ },
93
+
94
+ methods: {
95
+ // 示例1: 基础请求
96
+ async handleBasicRequest () {
97
+ const { success, data, error } = await this.basicRequest.execute({
98
+ queryParamsName: 'checkPlanListCRUD',
99
+ pageNum: 1,
100
+ pageSize: 5
101
+ })
102
+ if (success) {
103
+ this.requestResult = data
104
+ this.$message.success('基础请求成功')
105
+ } else if (error?.code !== 'ERR_DUPLICATE_REQUEST') {
106
+ this.$message.error('请求失败: ' + error?.message)
107
+ }
108
+ },
109
+
110
+ // 示例2: 全局 Loading 请求
111
+ async handleGlobalLoadingRequest () {
112
+ const { success, data, error } = await this.globalLoadingRequest.execute({
113
+ queryParamsName: 'checkPlanListCRUD',
114
+ pageNum: 1,
115
+ pageSize: 5
116
+ })
117
+ if (success) {
118
+ this.requestResult = data
119
+ this.$message.success('全局 Loading 请求成功')
120
+ } else if (error?.code !== 'ERR_DUPLICATE_REQUEST') {
121
+ this.$message.error('请求失败: ' + error?.message)
122
+ }
123
+ },
124
+
125
+ // 示例3: 去重请求
126
+ async handleDedupeRequest () {
127
+ // 快速点击多次,只会发送一次请求
128
+ const { success, data, error } = await this.dedupeRequest.execute({
129
+ queryParamsName: 'checkPlanListCRUD',
130
+ pageNum: 1,
131
+ pageSize: 5
132
+ })
133
+ if (success) {
134
+ this.requestResult = data
135
+ this.$message.success('去重请求成功 (查看控制台是否有去重警告)')
136
+ } else if (error?.code === 'ERR_DUPLICATE_REQUEST') {
137
+ // 重复请求被拦截,静默处理或提示
138
+ console.log('重复请求已被拦截')
139
+ } else {
140
+ this.$message.error('请求失败: ' + error?.message)
141
+ }
142
+ },
143
+
144
+ // 示例4: 组合请求
145
+ async handleComboRequest () {
146
+ const { success, data, error } = await this.comboRequest.execute({
147
+ queryParamsName: 'checkPlanListCRUD',
148
+ pageNum: 1,
149
+ pageSize: 5
150
+ })
151
+ if (success) {
152
+ this.requestResult = data
153
+ this.$message.success('组合请求成功')
154
+ } else if (error?.code !== 'ERR_DUPLICATE_REQUEST') {
155
+ this.$message.error('请求失败: ' + error?.message)
156
+ }
157
+ },
158
+
159
+ // 示例5: usePost 请求
160
+ async handlePostRequest () {
161
+ const { success, data, error } = await this.postRequest.execute({
162
+ queryParamsName: 'checkPlanListCRUD',
163
+ pageNum: 1,
164
+ pageSize: 5
165
+ })
166
+ if (success) {
167
+ this.requestResult = data
168
+ this.$message.success('usePost 请求成功')
169
+ } else if (error?.code !== 'ERR_DUPLICATE_REQUEST') {
170
+ this.$message.error('请求失败: ' + error?.message)
171
+ }
172
+ }
173
+ }
174
+ }
175
+ </script>
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Vue Composables 入口文件
3
+ * 提供 Composition API 风格的可复用逻辑
4
+ */
5
+
6
+ export { usePost, createPost, useRunLogic, createRunLogic } from './usePost'
@@ -0,0 +1,206 @@
1
+ /**
2
+ * 全局 Loading 管理
3
+ * 纯 JS 实现,直接操作 DOM,不依赖 Vue 组件
4
+ * 支持引用计数,多个并发请求时正确处理显示/隐藏
5
+ * 支持超时自动隐藏保护机制
6
+ */
7
+
8
+ // 全局状态
9
+ let isLoading = false
10
+ let loadingElement = null
11
+ let messageText = '加载中...'
12
+ let loadingCount = 0 // 引用计数,支持并发请求
13
+ let autoHideTimer = null // 超时自动隐藏定时器
14
+
15
+ // 配置
16
+ const DEFAULT_TIMEOUT = 30000 // 默认超时时间 30 秒
17
+ const CONTAINER_ID = 'global-loading-container'
18
+
19
+ /**
20
+ * 创建 Loading DOM 元素
21
+ */
22
+ function createLoadingElement (message) {
23
+ const container = document.createElement('div')
24
+ container.id = CONTAINER_ID
25
+ container.innerHTML = `
26
+ <div class="global-loading-mask">
27
+ <div class="global-loading-content">
28
+ <div class="global-loading-spinner">
29
+ <div class="ant-spin ant-spin-lg ant-spin-spinning">
30
+ <span class="ant-spin-dot ant-spin-dot-spin">
31
+ <i class="ant-spin-dot-item"></i>
32
+ <i class="ant-spin-dot-item"></i>
33
+ <i class="ant-spin-dot-item"></i>
34
+ <i class="ant-spin-dot-item"></i>
35
+ </span>
36
+ </div>
37
+ </div>
38
+ <p class="global-loading-message">${message}</p>
39
+ </div>
40
+ </div>
41
+ `
42
+ return container
43
+ }
44
+
45
+ /**
46
+ * 注入全局样式(只注入一次)
47
+ */
48
+ function injectStyles () {
49
+ if (document.getElementById('global-loading-styles')) return
50
+
51
+ const style = document.createElement('style')
52
+ style.id = 'global-loading-styles'
53
+ style.textContent = `
54
+ .global-loading-mask {
55
+ position: fixed;
56
+ top: 0;
57
+ left: 0;
58
+ right: 0;
59
+ bottom: 0;
60
+ background: rgba(0, 0, 0, 0.45);
61
+ z-index: 99999;
62
+ display: flex;
63
+ align-items: center;
64
+ justify-content: center;
65
+ }
66
+ .global-loading-content {
67
+ text-align: center;
68
+ }
69
+ .global-loading-message {
70
+ margin-top: 16px;
71
+ font-size: 14px;
72
+ color: #fff;
73
+ }
74
+ .global-loading-content .ant-spin-dot-item {
75
+ background-color: #fff !important;
76
+ }
77
+ `
78
+ document.head.appendChild(style)
79
+ }
80
+
81
+ /**
82
+ * 清除超时定时器
83
+ */
84
+ function clearAutoHideTimer () {
85
+ if (autoHideTimer) {
86
+ clearTimeout(autoHideTimer)
87
+ autoHideTimer = null
88
+ }
89
+ }
90
+
91
+ /**
92
+ * 设置超时自动隐藏
93
+ * @param {number} timeout - 超时时间(毫秒)
94
+ */
95
+ function setAutoHideTimer (timeout) {
96
+ clearAutoHideTimer()
97
+ if (timeout > 0) {
98
+ autoHideTimer = setTimeout(() => {
99
+ console.warn(`[GlobalLoading] 超时自动隐藏 (${timeout}ms)`)
100
+ forceHideGlobalLoading()
101
+ }, timeout)
102
+ }
103
+ }
104
+
105
+ /**
106
+ * 显示全局 Loading
107
+ * 支持引用计数,多次调用只显示一个 Loading
108
+ * @param {string|boolean} message - 提示信息,传 true 使用默认文字
109
+ * @param {number} timeout - 超时自动隐藏时间(毫秒),默认 30 秒,传 0 禁用
110
+ */
111
+ export function showGlobalLoading (message = '加载中...', timeout = DEFAULT_TIMEOUT) {
112
+ loadingCount++
113
+
114
+ // 已经在显示,只增加计数,重置超时
115
+ if (isLoading) {
116
+ setAutoHideTimer(timeout)
117
+ return
118
+ }
119
+
120
+ isLoading = true
121
+ messageText = typeof message === 'string' ? message : '加载中...'
122
+
123
+ // 注入样式
124
+ injectStyles()
125
+
126
+ // 创建并插入 DOM
127
+ loadingElement = createLoadingElement(messageText)
128
+ document.body.appendChild(loadingElement)
129
+
130
+ // 设置超时自动隐藏
131
+ setAutoHideTimer(timeout)
132
+ }
133
+
134
+ /**
135
+ * 隐藏全局 Loading
136
+ * 只有当所有请求都完成时才真正隐藏
137
+ */
138
+ export function hideGlobalLoading () {
139
+ loadingCount = Math.max(0, loadingCount - 1)
140
+
141
+ // 还有其他请求在进行中,不隐藏
142
+ if (loadingCount > 0) return
143
+
144
+ doHide()
145
+ }
146
+
147
+ /**
148
+ * 强制隐藏全局 Loading(重置计数器)
149
+ * 用于异常情况下的强制重置
150
+ */
151
+ export function forceHideGlobalLoading () {
152
+ loadingCount = 0
153
+ doHide()
154
+ }
155
+
156
+ /**
157
+ * 执行隐藏操作
158
+ */
159
+ function doHide () {
160
+ if (!isLoading) return
161
+
162
+ isLoading = false
163
+ clearAutoHideTimer()
164
+
165
+ // 移除 DOM
166
+ if (loadingElement && loadingElement.parentNode) {
167
+ loadingElement.parentNode.removeChild(loadingElement)
168
+ }
169
+ loadingElement = null
170
+ }
171
+
172
+ /**
173
+ * 获取当前 Loading 状态
174
+ * @returns {boolean}
175
+ */
176
+ export function isGlobalLoadingVisible () {
177
+ return isLoading
178
+ }
179
+
180
+ /**
181
+ * 获取当前 Loading 计数
182
+ * @returns {number}
183
+ */
184
+ export function getLoadingCount () {
185
+ return loadingCount
186
+ }
187
+
188
+ /**
189
+ * useGlobalLoading Hook(Vue Composition API 风格)
190
+ * @returns {{ show: Function, hide: Function, forceHide: Function, isVisible: Function }}
191
+ */
192
+ export function useGlobalLoading () {
193
+ return {
194
+ show: showGlobalLoading,
195
+ hide: hideGlobalLoading,
196
+ forceHide: forceHideGlobalLoading,
197
+ isVisible: isGlobalLoadingVisible
198
+ }
199
+ }
200
+
201
+ export default {
202
+ show: showGlobalLoading,
203
+ hide: hideGlobalLoading,
204
+ forceHide: forceHideGlobalLoading,
205
+ isVisible: isGlobalLoadingVisible
206
+ }
@@ -0,0 +1,221 @@
1
+ import Vue from 'vue'
2
+ import { post } from '@vue2-client/services/api/restTools'
3
+
4
+ /**
5
+ * @typedef {Object} RequestResult
6
+ * @property {boolean} success - 请求是否成功
7
+ * @property {any} data - 响应数据
8
+ * @property {Error|null} error - 错误信息
9
+ */
10
+
11
+ /**
12
+ * @typedef {Object} UsePostReturn
13
+ * @property {boolean} loading - 加载状态
14
+ * @property {Error|null} error - 错误信息
15
+ * @property {any} data - 响应数据
16
+ * @property {(params?: object, config?: object) => Promise<RequestResult>} execute - 执行请求
17
+ * @property {() => void} reset - 重置状态
18
+ */
19
+
20
+ /**
21
+ * Vue Composition API 风格的 POST 请求 Hook
22
+ * 提供响应式的 loading 状态管理,返回统一的结果结构
23
+ *
24
+ * @param {string} url - 请求地址
25
+ * @param {object} defaultConfig - 默认配置
26
+ * @param {boolean|string} defaultConfig.globalLoading - 是否显示全局 Loading
27
+ * @param {boolean} defaultConfig.dedupe - 是否启用请求去重(POST 默认开启,设为 false 可关闭)
28
+ * @returns {UsePostReturn}
29
+ *
30
+ * @example
31
+ * // 基础用法
32
+ * const { loading, execute } = usePost('/api/save')
33
+ * const { success, data, error } = await execute(formData)
34
+ * if (success) {
35
+ * message.success('保存成功')
36
+ * }
37
+ *
38
+ * @example
39
+ * // 在模板中绑定 loading 状态
40
+ * // <a-button :loading="loading" @click="handleSave">保存</a-button>
41
+ * const { loading, execute } = usePost('/api/save', { globalLoading: '保存中...' })
42
+ *
43
+ * @example
44
+ * // 获取响应式数据
45
+ * const { loading, data, error, execute } = usePost('/api/query')
46
+ * await execute({ id: 1 })
47
+ * // data 会自动更新,可直接在模板中使用
48
+ */
49
+ export function usePost (url, defaultConfig = {}) {
50
+ // 响应式状态
51
+ const state = Vue.observable({
52
+ loading: false,
53
+ error: null,
54
+ data: null
55
+ })
56
+
57
+ /**
58
+ * 执行请求
59
+ * @param {object} params - 请求参数
60
+ * @param {object} config - 本次请求的配置(覆盖默认配置)
61
+ * @returns {Promise<RequestResult>} 统一的结果结构
62
+ */
63
+ async function execute (params = {}, config = {}) {
64
+ state.loading = true
65
+ state.error = null
66
+
67
+ try {
68
+ const result = await post(url, params, { ...defaultConfig, ...config })
69
+ state.data = result
70
+ return { success: true, data: result, error: null }
71
+ } catch (err) {
72
+ state.error = err
73
+ return { success: false, data: null, error: err }
74
+ } finally {
75
+ state.loading = false
76
+ }
77
+ }
78
+
79
+ /**
80
+ * 重置状态
81
+ */
82
+ function reset () {
83
+ state.loading = false
84
+ state.error = null
85
+ state.data = null
86
+ }
87
+
88
+ // 返回响应式属性的 getter,确保在模板中能正确响应
89
+ return {
90
+ get loading () { return state.loading },
91
+ get error () { return state.error },
92
+ get data () { return state.data },
93
+ execute,
94
+ reset
95
+ }
96
+ }
97
+
98
+ export default usePost
99
+
100
+ /**
101
+ * @typedef {Object} UseRunLogicReturn
102
+ * @property {boolean} loading - 加载状态
103
+ * @property {Error|null} error - 错误信息
104
+ * @property {any} data - 响应数据
105
+ * @property {(params?: object, overrideOptions?: object) => Promise<RequestResult>} execute - 执行请求
106
+ * @property {() => void} reset - 重置状态
107
+ */
108
+
109
+ /**
110
+ * Vue Composition API 风格的 runLogic Hook
111
+ * 用于调用后端业务逻辑,提供响应式的 loading 状态管理
112
+ *
113
+ * @param {string} logicName - 业务逻辑名称
114
+ * @param {object} options - 配置选项
115
+ * @param {string} options.serviceName - 服务名称,默认为 VUE_APP_SYSTEM_NAME
116
+ * @param {boolean} options.isDev - 是否为开发环境
117
+ * @param {boolean|string} options.globalLoading - 是否显示全局 Loading
118
+ * @param {boolean} options.dedupe - 是否启用请求去重(POST 默认开启,设为 false 可关闭)
119
+ * @returns {UseRunLogicReturn}
120
+ *
121
+ * @example
122
+ * // 基础用法
123
+ * const { loading, execute, data } = useRunLogic('getUserInfo')
124
+ * const { success, data: result } = await execute({ userId: 1 })
125
+ * if (success) {
126
+ * console.log(result)
127
+ * }
128
+ *
129
+ * @example
130
+ * // 带全局 Loading
131
+ * const { loading, execute } = useRunLogic('saveOrder', {
132
+ * globalLoading: '保存中...',
133
+ * dedupe: true
134
+ * })
135
+ * // 模板: <a-button :loading="loading" @click="handleSave">保存</a-button>
136
+ *
137
+ * @example
138
+ * // 指定服务名称
139
+ * const { execute } = useRunLogic('queryData', {
140
+ * serviceName: 'af-custom',
141
+ * isDev: false
142
+ * })
143
+ */
144
+ export function useRunLogic (logicName, options = {}) {
145
+ const {
146
+ serviceName = process.env.VUE_APP_SYSTEM_NAME,
147
+ isDev = false,
148
+ globalLoading = false,
149
+ dedupe = false
150
+ } = options
151
+
152
+ // 响应式状态
153
+ const state = Vue.observable({
154
+ loading: false,
155
+ error: null,
156
+ data: null
157
+ })
158
+
159
+ /**
160
+ * 构建请求 URL
161
+ * @param {string} svcName - 服务名称
162
+ * @param {boolean} dev - 是否开发环境
163
+ * @returns {string}
164
+ */
165
+ function buildUrl (svcName, dev) {
166
+ const apiPre = dev ? '/devApi/' : '/api/'
167
+ return `${apiPre}${svcName}/logic/${logicName}`
168
+ }
169
+
170
+ /**
171
+ * 执行业务逻辑
172
+ * @param {object} params - 请求参数
173
+ * @param {object} overrideOptions - 本次请求的配置(覆盖默认配置)
174
+ * @returns {Promise<RequestResult>} 统一的结果结构
175
+ */
176
+ async function execute (params = {}, overrideOptions = {}) {
177
+ state.loading = true
178
+ state.error = null
179
+
180
+ // 合并配置
181
+ const finalServiceName = overrideOptions.serviceName || serviceName
182
+ const finalIsDev = overrideOptions.isDev !== undefined ? overrideOptions.isDev : isDev
183
+
184
+ // 构建请求 URL
185
+ const url = buildUrl(finalServiceName, finalIsDev)
186
+
187
+ // 构建请求配置
188
+ const requestConfig = {
189
+ globalLoading: overrideOptions.globalLoading !== undefined ? overrideOptions.globalLoading : globalLoading,
190
+ dedupe: overrideOptions.dedupe !== undefined ? overrideOptions.dedupe : dedupe
191
+ }
192
+
193
+ try {
194
+ const result = await post(url, params, requestConfig)
195
+ state.data = result
196
+ return { success: true, data: result, error: null }
197
+ } catch (err) {
198
+ state.error = err
199
+ return { success: false, data: null, error: err }
200
+ } finally {
201
+ state.loading = false
202
+ }
203
+ }
204
+
205
+ /**
206
+ * 重置状态
207
+ */
208
+ function reset () {
209
+ state.loading = false
210
+ state.error = null
211
+ state.data = null
212
+ }
213
+
214
+ return {
215
+ get loading () { return state.loading },
216
+ get error () { return state.error },
217
+ get data () { return state.data },
218
+ execute,
219
+ reset
220
+ }
221
+ }