sohelp-eleplus 1.1.26 → 1.1.28
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/components.js +1 -0
- package/icons/flag/README.md +2 -2
- package/icons/flag/index.js +0 -1
- package/package.json +1 -1
- package/sohelp-ace-editor/README.md +32 -42
- package/sohelp-ace-editor/index.vue +166 -156
- package/sohelp-api-doc/README.md +36 -0
- package/sohelp-api-doc/index.vue +160 -0
- package/sohelp-application-select/README.md +9 -7
- package/sohelp-application-select/index.vue +10 -13
- package/sohelp-autocode/README.md +14 -26
- package/sohelp-calendar-view/README.md +9 -7
- package/sohelp-calendar-view/index.vue +10 -9
- package/sohelp-card/README.md +15 -17
- package/sohelp-card/index.vue +1 -1
- package/sohelp-card-view/README.md +9 -7
- package/sohelp-card-view/index.vue +10 -9
- package/sohelp-condition/README.md +29 -49
- package/sohelp-condition/index.vue +2 -1
- package/sohelp-country-select/README.md +15 -123
- package/sohelp-country-select/index.vue +1 -1
- package/sohelp-cry-input/README.md +19 -195
- package/sohelp-cry-input/index.vue +6 -2
- package/sohelp-date/README.md +12 -15
- package/sohelp-datetime/README.md +15 -17
- package/sohelp-datetime-picker/README.md +18 -18
- package/sohelp-datetime-picker/index.vue +11 -4
- package/sohelp-datetime-range/README.md +20 -23
- package/sohelp-demo-block/README.md +43 -0
- package/sohelp-demo-block/index.vue +229 -0
- package/sohelp-dict/README.md +28 -23
- package/sohelp-dict/index.vue +17 -17
- package/sohelp-drawer/README.md +28 -26
- package/sohelp-drop-card/README.md +29 -28
- package/sohelp-drop-card/index.vue +0 -1
- package/sohelp-dyn-select/README.md +31 -16
- package/sohelp-dyn-select/index.vue +65 -67
- package/sohelp-dyn-tree/README.md +26 -20
- package/sohelp-dyn-tree/index.vue +2 -2
- package/sohelp-dyn-tree-select/README.md +28 -19
- package/sohelp-dyn-tree-select/index.vue +23 -7
- package/sohelp-entity-form/README.md +65 -30
- package/sohelp-entity-form/index.vue +3 -2
- package/sohelp-entity-grid/README.md +13 -11
- package/sohelp-entity-grid/index.vue +1 -1
- package/sohelp-file-upload/README.md +25 -27
- package/sohelp-file-upload/index.vue +1 -1
- package/sohelp-filter-scheme/README.md +34 -30
- package/sohelp-filter-scheme/index.vue +2 -2
- package/sohelp-grid/README.md +52 -33
- package/sohelp-grid/index.vue +41 -39
- package/sohelp-grid/js/SohelpGridConfig.js +3 -3
- package/sohelp-grid/js/useSohelpGridConfig.js +4 -6
- package/sohelp-grid-select/README.md +32 -27
- package/sohelp-grid-select/index.vue +6 -5
- package/sohelp-grid-view/README.md +51 -22
- package/sohelp-grid-view-select/README.md +33 -25
- package/sohelp-grid-view-select/index.vue +2 -1
- package/sohelp-group-view/README.md +14 -4
- package/sohelp-group-view/index.vue +10 -9
- package/sohelp-icon-select/README.md +14 -12
- package/sohelp-image-upload/README.md +27 -27
- package/sohelp-image-upload/index.vue +2 -2
- package/sohelp-import/README.md +25 -24
- package/sohelp-input/README.md +27 -11
- package/sohelp-input/index.vue +15 -2
- package/sohelp-input-tag/README.md +53 -0
- package/sohelp-input-tag/index.vue +337 -0
- package/sohelp-modal/README.md +42 -16
- package/sohelp-modal/index.vue +21 -4
- package/sohelp-modal-select/README.md +745 -0
- package/sohelp-modal-select/index.vue +705 -0
- package/sohelp-module/README.md +24 -13
- package/sohelp-number-input/README.md +15 -8
- package/sohelp-number-input/index.vue +3 -0
- package/sohelp-number-range/README.md +22 -12
- package/sohelp-number-range/index.vue +3 -11
- package/sohelp-org-modal-select/README.md +47 -0
- package/sohelp-org-modal-select/index.vue +411 -0
- package/sohelp-org-select/README.md +23 -10
- package/sohelp-org-select/index.vue +41 -24
- package/sohelp-org-tree/README.md +19 -7
- package/sohelp-org-tree/index.vue +1 -2
- package/sohelp-org-tree-select/README.md +22 -11
- package/sohelp-org-tree-select/index.vue +1 -2
- package/sohelp-org-user-tree/README.md +19 -7
- package/sohelp-org-user-tree/index.vue +1 -2
- package/sohelp-org-user-tree-select/README.md +8 -3
- package/sohelp-org-user-tree-select/index.vue +8 -7
- package/sohelp-page/README.md +20 -11
- package/sohelp-page/index.vue +1 -1
- package/sohelp-pagination/README.md +14 -6
- package/sohelp-pagination/index.vue +1 -1
- package/sohelp-power/README.md +34 -19
- package/sohelp-power/index.vue +2 -2
- package/sohelp-pro-form/README.md +64 -21
- package/sohelp-pro-layout/README.md +10 -4
- package/sohelp-pro-layout/index.vue +8 -7
- package/sohelp-pro-table/README.md +30 -6
- package/sohelp-process/README.md +26 -13
- package/sohelp-process/index.vue +6 -6
- package/sohelp-rate/README.md +24 -12
- package/sohelp-rate/index.vue +5 -1
- package/sohelp-relation/README.md +10 -4
- package/sohelp-relation/index.vue +8 -7
- package/sohelp-relation-modal-select/README.md +41 -0
- package/sohelp-relation-modal-select/index.vue +70 -0
- package/sohelp-rich-text/README.md +29 -11
- package/sohelp-rich-text/index.vue +21 -20
- package/sohelp-richtext/README.md +12 -2
- package/sohelp-richtext/index.vue +8 -6
- package/sohelp-role-modal-select/README.md +45 -0
- package/sohelp-role-modal-select/index.vue +111 -0
- package/sohelp-role-select/README.md +18 -10
- package/sohelp-role-select/index.vue +36 -27
- package/sohelp-search/README.md +12 -4
- package/sohelp-search/index.vue +2 -2
- package/sohelp-search-pro-form/README.md +15 -1
- package/sohelp-search-pro-form/index.vue +2 -1
- package/sohelp-select/README.md +31 -30
- package/sohelp-select/index.vue +79 -84
- package/sohelp-split-panel/README.md +17 -18
- package/sohelp-switch/README.md +21 -19
- package/sohelp-switch/index.vue +34 -33
- package/sohelp-table/README.md +35 -27
- package/sohelp-table/index.vue +110 -109
- package/sohelp-table-select/README.md +55 -0
- package/sohelp-tenant-select/README.md +19 -18
- package/sohelp-tenant-select/index.vue +105 -109
- package/sohelp-text/README.md +16 -10
- package/sohelp-text/index.vue +5 -5
- package/sohelp-textarea-input/README.md +19 -12
- package/sohelp-time/README.md +11 -10
- package/sohelp-tree/README.md +24 -19
- package/sohelp-tree/index.vue +21 -23
- package/sohelp-tree-select/README.md +23 -10
- package/sohelp-user-modal-select/README.md +739 -0
- package/sohelp-user-modal-select/index.vue +87 -0
- package/sohelp-user-select/README.md +26 -15
- package/sohelp-user-select/index.vue +6 -2
- package/sohelp-user-tag/README.md +5 -7
- package/sohelp-user-tag/index.vue +8 -8
- package/sohelp-user-tree/README.md +5 -8
- package/sohelp-user-tree/index.vue +8 -7
- package/sohelp-vform-drawer/README.md +36 -18
- package/sohelp-vform-drawer/index.vue +2 -2
- package/sohelp-vform-eleplus/README.md +33 -31
- package/sohelp-vform-eleplus/index.vue +2 -2
- package/sohelp-vform-eleplus/tinymce/langs/zh_CN.js +461 -461
- package/sohelp-vform-eleplus/tinymce/langs/zh_TW.js +418 -418
- package/sohelp-vform-eleplus/tinymce/skins/content/dark/content.css +72 -72
- package/sohelp-vform-eleplus/tinymce/skins/content/dark/content.min.css +7 -7
- package/sohelp-vform-eleplus/tinymce/skins/content/default/content.css +67 -67
- package/sohelp-vform-eleplus/tinymce/skins/content/default/content.min.css +7 -7
- package/sohelp-vform-eleplus/tinymce/skins/content/document/content.css +72 -72
- package/sohelp-vform-eleplus/tinymce/skins/content/document/content.min.css +7 -7
- package/sohelp-vform-eleplus/tinymce/skins/content/writer/content.css +68 -68
- package/sohelp-vform-eleplus/tinymce/skins/content/writer/content.min.css +7 -7
- package/sohelp-vform-eleplus/tinymce/skins/ui/oxide/content.css +732 -732
- package/sohelp-vform-eleplus/tinymce/skins/ui/oxide/content.inline.css +726 -726
- package/sohelp-vform-eleplus/tinymce/skins/ui/oxide/content.inline.min.css +7 -7
- package/sohelp-vform-eleplus/tinymce/skins/ui/oxide/content.min.css +7 -7
- package/sohelp-vform-eleplus/tinymce/skins/ui/oxide/content.mobile.css +29 -29
- package/sohelp-vform-eleplus/tinymce/skins/ui/oxide/content.mobile.min.css +7 -7
- package/sohelp-vform-eleplus/tinymce/skins/ui/oxide/skin.css +3047 -3047
- package/sohelp-vform-eleplus/tinymce/skins/ui/oxide/skin.min.css +7 -7
- package/sohelp-vform-eleplus/tinymce/skins/ui/oxide/skin.mobile.css +673 -673
- package/sohelp-vform-eleplus/tinymce/skins/ui/oxide/skin.mobile.min.css +7 -7
- package/sohelp-vform-eleplus/tinymce/skins/ui/oxide/skin.shadowdom.css +37 -37
- package/sohelp-vform-eleplus/tinymce/skins/ui/oxide/skin.shadowdom.min.css +7 -7
- package/sohelp-vform-eleplus/tinymce/skins/ui/oxide-dark/content.css +714 -714
- package/sohelp-vform-eleplus/tinymce/skins/ui/oxide-dark/content.inline.css +726 -726
- package/sohelp-vform-eleplus/tinymce/skins/ui/oxide-dark/content.inline.min.css +7 -7
- package/sohelp-vform-eleplus/tinymce/skins/ui/oxide-dark/content.min.css +7 -7
- package/sohelp-vform-eleplus/tinymce/skins/ui/oxide-dark/content.mobile.css +29 -29
- package/sohelp-vform-eleplus/tinymce/skins/ui/oxide-dark/content.mobile.min.css +7 -7
- package/sohelp-vform-eleplus/tinymce/skins/ui/oxide-dark/skin.css +3047 -3047
- package/sohelp-vform-eleplus/tinymce/skins/ui/oxide-dark/skin.min.css +7 -7
- package/sohelp-vform-eleplus/tinymce/skins/ui/oxide-dark/skin.mobile.css +673 -673
- package/sohelp-vform-eleplus/tinymce/skins/ui/oxide-dark/skin.mobile.min.css +7 -7
- package/sohelp-vform-eleplus/tinymce/skins/ui/oxide-dark/skin.shadowdom.css +37 -37
- package/sohelp-vform-eleplus/tinymce/skins/ui/oxide-dark/skin.shadowdom.min.css +7 -7
- package/sohelp-vform-modal/README.md +36 -18
- package/sohelp-vform-modal/index.vue +2 -2
- package/sohelp-vform-select/README.md +9 -7
- package/sohelp-vform-select/index.vue +8 -7
- package/sohelp-vxe-grid/DefaultGridOptions.js +5 -3
- package/sohelp-vxe-grid/DefaultProps.js +0 -1
- package/sohelp-vxe-grid/README.md +540 -35
- package/sohelp-vxe-grid/SohelpGridConfig.js +8 -6
- package/sohelp-vxe-grid/index.vue +141 -94
- package/sohelp-vxe-grid-select/README.md +41 -26
- package/sohelp-vxe-table/README.md +23 -20
- package/sohelp-vxe-table/index.vue +5 -4
- package/sohelp-workflow/README.md +21 -17
- package/sohelp-workflow/index.vue +25 -22
- package/sohelp-workflow-drawer/README.md +41 -28
- package/sohelp-workflow-drawer/components/table.vue +7 -1
- package/sohelp-workflow-drawer/index.vue +86 -71
- package/sohelp-workflow-drawer/js/index.js +15 -13
- package/style/index.scss +0 -0
- package/utils/safe-eval.js +89 -0
- package/sohelp-dyn-select/props.js +0 -67
- package/sohelp-user-select/index.vue~ +0 -53
- package/sohelp-user-select/props.js +0 -71
|
@@ -1,38 +1,51 @@
|
|
|
1
|
-
# SohelpWorkflowDrawer
|
|
1
|
+
# SohelpWorkflowDrawer 工作流审批抽屉
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
基于 `ele-drawer` 封装的工作流审批详情抽屉组件,包含表单、流程图、表格和时间轴四个 Tab 页,支持同意、拒绝、委派、加签、减签等审批操作。
|
|
4
4
|
|
|
5
|
-
##
|
|
6
|
-
|
|
7
|
-
| Name | Type | Default | Description |
|
|
8
|
-
| :--- | :--- | :--- | :--- |
|
|
9
|
-
| `modelValue` | `Boolean` | - | Controls the visibility of the drawer. |
|
|
10
|
-
| `data` | `Object` | - | Requires `{ id, refid }` to fetch workflow details. |
|
|
11
|
-
| `showOpera` | `Boolean` | `true` | Whether to show operation buttons (Agree, Reject, etc.). |
|
|
12
|
-
|
|
13
|
-
## Events
|
|
14
|
-
|
|
15
|
-
| Name | Parameters | Description |
|
|
16
|
-
| :--- | :--- | :--- |
|
|
17
|
-
| `update:modelValue` | `(visible)` | Updates the visibility state. |
|
|
18
|
-
| `reload` | - | Triggered when an operation is completed successfully. |
|
|
19
|
-
| `close` | - | Triggered when the drawer is closed. |
|
|
20
|
-
|
|
21
|
-
## Methods
|
|
22
|
-
|
|
23
|
-
| Name | Description |
|
|
24
|
-
| :--- | :--- |
|
|
25
|
-
| `show(params)` | Opens the drawer with the given parameters. |
|
|
26
|
-
| `close()` | Closes the drawer. |
|
|
27
|
-
|
|
28
|
-
## Usage
|
|
5
|
+
## 基础用法
|
|
29
6
|
|
|
30
7
|
```vue
|
|
31
8
|
<template>
|
|
32
9
|
<sohelp-workflow-drawer
|
|
33
10
|
v-model="visible"
|
|
34
|
-
:data="
|
|
35
|
-
@reload="
|
|
11
|
+
:data="rowData"
|
|
12
|
+
@reload="reloadTable"
|
|
13
|
+
@close="onClose"
|
|
14
|
+
ref="drawerRef"
|
|
36
15
|
/>
|
|
37
16
|
</template>
|
|
17
|
+
|
|
18
|
+
<script setup>
|
|
19
|
+
import { ref } from 'vue';
|
|
20
|
+
const visible = ref(false);
|
|
21
|
+
const rowData = ref({ id: '', refid: '' });
|
|
22
|
+
const drawerRef = ref(null);
|
|
23
|
+
const reloadTable = () => { /* 刷新列表 */ };
|
|
24
|
+
const onClose = () => { /* 关闭回调 */ };
|
|
25
|
+
|
|
26
|
+
// 通过 expose 方法打开
|
|
27
|
+
drawerRef.value?.show({ id: '123', refid: 'myRefId' });
|
|
28
|
+
</script>
|
|
38
29
|
```
|
|
30
|
+
|
|
31
|
+
## 属性 (Props)
|
|
32
|
+
|
|
33
|
+
| 属性名 | 类型 | 默认值 | 必填 | 说明 |
|
|
34
|
+
| --- | --- | --- | --- | --- |
|
|
35
|
+
| modelValue (v-model) | Boolean | - | 否 | 控制抽屉显示/隐藏 |
|
|
36
|
+
| data | Object | - | 否 | 审批数据对象,需包含 `id` 和 `refid` |
|
|
37
|
+
|
|
38
|
+
## 事件 (Events)
|
|
39
|
+
|
|
40
|
+
| 事件名 | 回调参数 | 说明 |
|
|
41
|
+
| --- | --- | --- |
|
|
42
|
+
| update:modelValue | `value: Boolean` | 抽屉显示状态变化 |
|
|
43
|
+
| update:data | `value: Object` | 数据更新 |
|
|
44
|
+
| opera | - | 操作事件 |
|
|
45
|
+
| reload | - | 审批完成后请求刷新列表 |
|
|
46
|
+
| close | - | 抽屉关闭时触发 |
|
|
47
|
+
|
|
48
|
+
## 公开方法 (Expose)
|
|
49
|
+
|
|
50
|
+
- `show(params)` - 打开抽屉并设置数据,`params` 需含 `id` 和 `refid`
|
|
51
|
+
- `close()` - 关闭抽屉
|
|
@@ -16,7 +16,13 @@
|
|
|
16
16
|
<template #actorList="{ row }">
|
|
17
17
|
<div style="display: flex; gap: 5px; flex-wrap: wrap">
|
|
18
18
|
<span v-for="item in row?.actorList" :key="item.actor_id">
|
|
19
|
-
<vxe-tag status="primary">{{ item
|
|
19
|
+
<vxe-tag status="primary">{{ item?.actor_name }}</vxe-tag>
|
|
20
|
+
</span>
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
<div style="display: flex; gap: 5px; flex-wrap: wrap" v-if="row.type != 'done'">
|
|
24
|
+
<span v-for="item in row?.assigneeList" :key="item.actor_id">
|
|
25
|
+
<vxe-tag status="info">{{ item?.name }}</vxe-tag>
|
|
20
26
|
</span>
|
|
21
27
|
</div>
|
|
22
28
|
</template>
|
|
@@ -63,23 +63,44 @@
|
|
|
63
63
|
|
|
64
64
|
<template #footer>
|
|
65
65
|
<el-button @click="userModal = false">取消</el-button>
|
|
66
|
-
<el-button
|
|
66
|
+
<el-button
|
|
67
|
+
type="primary"
|
|
68
|
+
@click="saveByUser(todoType, users)"
|
|
69
|
+
v-loading="loading"
|
|
70
|
+
:disabled="!users.length"
|
|
67
71
|
>{{ moreOption[todoType] }}
|
|
68
72
|
</el-button>
|
|
69
73
|
</template>
|
|
70
74
|
</ele-modal>
|
|
71
75
|
|
|
72
76
|
<template #footer>
|
|
73
|
-
<el-button plain size="small" @click="updateModelValue(false)"
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
+
<el-button plain size="small" @click="updateModelValue(false)"
|
|
78
|
+
>关闭</el-button
|
|
79
|
+
>
|
|
80
|
+
<span v-if="showOpera && data">
|
|
81
|
+
<el-button
|
|
82
|
+
v-permission="refidPrefix + 'workflow.agree'"
|
|
83
|
+
type="primary"
|
|
84
|
+
size="small"
|
|
85
|
+
@click="openModal('agree')"
|
|
77
86
|
>
|
|
78
|
-
|
|
79
|
-
|
|
87
|
+
同意
|
|
88
|
+
</el-button>
|
|
89
|
+
<el-button
|
|
90
|
+
v-permission="refidPrefix + 'workflow.reject'"
|
|
91
|
+
type="danger"
|
|
92
|
+
size="small"
|
|
93
|
+
@click="openModal('reject')"
|
|
94
|
+
>
|
|
95
|
+
拒绝
|
|
96
|
+
</el-button>
|
|
97
|
+
<ele-dropdown
|
|
98
|
+
v-if="getMore.length > 0"
|
|
99
|
+
trigger="click"
|
|
100
|
+
:items="getMore"
|
|
101
|
+
@command="onOperate"
|
|
80
102
|
>
|
|
81
|
-
|
|
82
|
-
<el-button plain="" size="small" title="更多" :icon="MoreFilled"></el-button>
|
|
103
|
+
<el-button size="small" :icon="MoreFilled" title="更多" />
|
|
83
104
|
</ele-dropdown>
|
|
84
105
|
</span>
|
|
85
106
|
</template>
|
|
@@ -87,12 +108,13 @@
|
|
|
87
108
|
</template>
|
|
88
109
|
|
|
89
110
|
<script setup>
|
|
90
|
-
import { buttonAuth, getTodoDetail, moreOption, todoOperate } from '
|
|
111
|
+
import { buttonAuth, getTodoDetail, moreOption, todoOperate } from './js';
|
|
112
|
+
|
|
91
113
|
import { EleMessage } from '@/components/ele-admin-plus/components';
|
|
92
114
|
import { MoreFilled } from '@element-plus/icons-vue';
|
|
93
115
|
import { ElMessageBox } from 'element-plus/es';
|
|
94
116
|
import { usePermission } from '@/utils/use-permission';
|
|
95
|
-
import { computed, reactive, ref
|
|
117
|
+
import { computed, reactive, ref } from 'vue';
|
|
96
118
|
import FormTab from './components/form.vue';
|
|
97
119
|
import TableTab from './components/table.vue';
|
|
98
120
|
import TimelineTab from './components/timeline.vue';
|
|
@@ -103,14 +125,18 @@
|
|
|
103
125
|
|
|
104
126
|
const props = defineProps({
|
|
105
127
|
modelValue: Boolean,
|
|
106
|
-
data: Object
|
|
107
|
-
showOpera: {
|
|
108
|
-
type: Boolean,
|
|
109
|
-
default: true
|
|
110
|
-
}
|
|
128
|
+
data: Object
|
|
111
129
|
});
|
|
112
130
|
|
|
113
|
-
const
|
|
131
|
+
const showOpera = ref(false);
|
|
132
|
+
|
|
133
|
+
const emit = defineEmits([
|
|
134
|
+
'opera',
|
|
135
|
+
'update:data',
|
|
136
|
+
'update:modelValue',
|
|
137
|
+
'reload',
|
|
138
|
+
'close'
|
|
139
|
+
]);
|
|
114
140
|
|
|
115
141
|
const tabs = reactive([
|
|
116
142
|
{ label: '表单', name: 'form' },
|
|
@@ -120,23 +146,26 @@
|
|
|
120
146
|
]);
|
|
121
147
|
const active = ref('form');
|
|
122
148
|
const detail = ref();
|
|
149
|
+
const taskData = ref(null);
|
|
123
150
|
|
|
124
151
|
const todoType = ref(null);
|
|
125
152
|
const userModal = ref(false);
|
|
126
|
-
const drawerVisible = ref(false);
|
|
127
153
|
const loading = ref(false);
|
|
128
154
|
const users = ref([]);
|
|
129
155
|
|
|
156
|
+
const todoDrawerRef = ref(null);
|
|
130
157
|
const approvalModalVisible = ref(false);
|
|
131
158
|
const approvalData = reactive({
|
|
132
159
|
id: '',
|
|
133
160
|
refid: ''
|
|
134
161
|
});
|
|
135
162
|
|
|
136
|
-
/**
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
163
|
+
/** refid前缀 */
|
|
164
|
+
const refidPrefix = computed(() => {
|
|
165
|
+
return props.data?.refid?.split('!')?.[0] + ':' || '';
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
/** 显示详情 */
|
|
140
169
|
const show = (params = {}) => {
|
|
141
170
|
emit('update:data', params);
|
|
142
171
|
emit('update:modelValue', true);
|
|
@@ -147,35 +176,33 @@
|
|
|
147
176
|
emit('update:modelValue', value);
|
|
148
177
|
};
|
|
149
178
|
|
|
150
|
-
/**
|
|
151
|
-
* 打开抽屉
|
|
152
|
-
*/
|
|
179
|
+
/** 打开抽屉 */
|
|
153
180
|
const open = async () => {
|
|
154
|
-
emit('update:showOpera', false);
|
|
155
181
|
const { id, refid } = props.data;
|
|
156
182
|
if (id && refid) {
|
|
157
183
|
await getDetail({ refid, id });
|
|
158
|
-
//
|
|
159
|
-
SohelpHttp.get('/engine/web/workflow/getMyTask', {
|
|
184
|
+
// 获取可审批的任务
|
|
185
|
+
SohelpHttp.get('/engine/web/workflow/getMyTask', {
|
|
186
|
+
refid,
|
|
187
|
+
id
|
|
188
|
+
}).then((res) => {
|
|
160
189
|
if (res.meta.success) {
|
|
161
|
-
|
|
190
|
+
taskData.value = res.data;
|
|
191
|
+
showOpera.value = !!res.data?.id;
|
|
192
|
+
} else {
|
|
193
|
+
EleMessage.error(res.meta?.message);
|
|
162
194
|
}
|
|
163
195
|
});
|
|
164
196
|
}
|
|
165
197
|
};
|
|
166
198
|
|
|
167
|
-
/**
|
|
168
|
-
* 关闭抽屉
|
|
169
|
-
*/
|
|
199
|
+
/** 关闭抽屉 */
|
|
170
200
|
const close = () => {
|
|
171
201
|
active.value = 'form';
|
|
172
202
|
emit('close');
|
|
173
203
|
};
|
|
174
204
|
|
|
175
|
-
/**
|
|
176
|
-
* 获取详情
|
|
177
|
-
* @param params
|
|
178
|
-
*/
|
|
205
|
+
/** 获取详情 */
|
|
179
206
|
const getDetail = async (params) => {
|
|
180
207
|
loading.value = true;
|
|
181
208
|
const res = await getTodoDetail(params);
|
|
@@ -187,67 +214,61 @@
|
|
|
187
214
|
}
|
|
188
215
|
};
|
|
189
216
|
|
|
190
|
-
/**
|
|
191
|
-
* 更多操作按钮
|
|
192
|
-
*/
|
|
217
|
+
/** 更多操作按钮 */
|
|
193
218
|
const getMore = computed(() => {
|
|
194
219
|
const exclude = ['agree', 'reject', 'batchAgree', 'batchReject', 'submit'];
|
|
195
220
|
return Object.entries(moreOption)
|
|
196
|
-
.filter(
|
|
197
|
-
|
|
221
|
+
.filter(
|
|
222
|
+
([key]) =>
|
|
223
|
+
!exclude.includes(key) &&
|
|
224
|
+
permission.hasPermission(refidPrefix.value + buttonAuth[key])
|
|
225
|
+
)
|
|
226
|
+
.map(([command, title]) => ({ command, title }));
|
|
198
227
|
});
|
|
199
228
|
|
|
200
|
-
/**
|
|
201
|
-
* 同意、拒绝弹窗
|
|
202
|
-
* @param type
|
|
203
|
-
*/
|
|
229
|
+
/** 同意、拒绝弹窗 */
|
|
204
230
|
const openModal = (type) => {
|
|
205
231
|
todoType.value = type;
|
|
206
|
-
const id = props.data.id;
|
|
207
232
|
Object.assign(approvalData, {
|
|
208
|
-
id: id,
|
|
233
|
+
id: props.data.id,
|
|
209
234
|
refid: props.data.refid
|
|
210
235
|
});
|
|
211
236
|
approvalModalVisible.value = true;
|
|
212
237
|
};
|
|
213
238
|
|
|
214
|
-
/**
|
|
215
|
-
* 选择用户弹窗
|
|
216
|
-
*/
|
|
239
|
+
/** 选择用户弹窗 */
|
|
217
240
|
const openUserModal = () => {
|
|
218
241
|
users.value = todoType.value === 'delegate' ? '' : [];
|
|
219
242
|
};
|
|
220
243
|
|
|
221
|
-
/**
|
|
222
|
-
* 更多操作
|
|
223
|
-
* @param type 类型
|
|
224
|
-
* @param row
|
|
225
|
-
*/
|
|
244
|
+
/** 更多操作 */
|
|
226
245
|
const onOperate = (type) => {
|
|
227
246
|
todoType.value = type;
|
|
228
247
|
|
|
229
248
|
// 委派、加签、减签
|
|
230
249
|
if (['delegate', 'addSign', 'removeSign'].includes(type)) {
|
|
231
250
|
userModal.value = true;
|
|
232
|
-
return
|
|
251
|
+
return;
|
|
233
252
|
}
|
|
234
253
|
|
|
235
|
-
|
|
236
|
-
|
|
254
|
+
const data = {
|
|
255
|
+
id: props.data.id,
|
|
256
|
+
refid: props.data.refid
|
|
237
257
|
};
|
|
258
|
+
|
|
238
259
|
// 跳转
|
|
239
260
|
if (type === 'jump') {
|
|
240
|
-
data.nodeKey = props.data
|
|
261
|
+
data.nodeKey = props.data?.nodeKey || '';
|
|
241
262
|
}
|
|
242
263
|
|
|
243
264
|
ElMessageBox.confirm(`确定要${moreOption[type]}吗?`, '系统提示', {
|
|
244
265
|
type: 'danger',
|
|
245
266
|
draggable: false
|
|
246
267
|
})
|
|
247
|
-
.then(
|
|
268
|
+
.then(() => {
|
|
248
269
|
save(type, data);
|
|
249
270
|
})
|
|
250
|
-
.catch((
|
|
271
|
+
.catch(() => {});
|
|
251
272
|
};
|
|
252
273
|
|
|
253
274
|
// 更新table
|
|
@@ -256,22 +277,16 @@
|
|
|
256
277
|
emit('reload');
|
|
257
278
|
};
|
|
258
279
|
|
|
259
|
-
/**
|
|
260
|
-
* 委派,加签,减签保存
|
|
261
|
-
* @param type
|
|
262
|
-
*/
|
|
280
|
+
/** 委派,加签,减签保存 */
|
|
263
281
|
const saveByUser = (type) => {
|
|
264
282
|
save(type, {
|
|
265
283
|
id: props.data.id,
|
|
284
|
+
refid: props.data.refid,
|
|
266
285
|
[type === 'delegate' ? 'userId' : 'users']: users.value
|
|
267
286
|
});
|
|
268
287
|
};
|
|
269
288
|
|
|
270
|
-
/**
|
|
271
|
-
* 保存
|
|
272
|
-
* @param type
|
|
273
|
-
* @param data
|
|
274
|
-
*/
|
|
289
|
+
/** 保存 */
|
|
275
290
|
const save = (type, data) => {
|
|
276
291
|
loading.value = true;
|
|
277
292
|
todoOperate(type, data)
|
|
@@ -279,7 +294,7 @@
|
|
|
279
294
|
loading.value = false;
|
|
280
295
|
EleMessage.success(msg);
|
|
281
296
|
done();
|
|
282
|
-
if (type
|
|
297
|
+
if (type === 'agree' || type === 'reject') {
|
|
283
298
|
todoDrawerRef.value?.closeModal();
|
|
284
299
|
}
|
|
285
300
|
if (['delegate', 'addSign', 'removeSign'].includes(type)) {
|
|
@@ -15,18 +15,18 @@ export const moreOption = {
|
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
export const buttonAuth = {
|
|
18
|
-
agree: '
|
|
19
|
-
reject: '
|
|
20
|
-
submit: '
|
|
21
|
-
reclaim: '
|
|
22
|
-
delegate: '
|
|
18
|
+
agree: 'workflow.agree',
|
|
19
|
+
reject: 'workflow.reject',
|
|
20
|
+
submit: 'workflow.submit',
|
|
21
|
+
reclaim: 'workflow.reclaim',
|
|
22
|
+
delegate: 'workflow.delegate',
|
|
23
23
|
complete: 'todo.wf.complete',
|
|
24
|
-
addSign: '
|
|
25
|
-
removeSign: '
|
|
26
|
-
jump: '
|
|
27
|
-
jumpPrevious: '
|
|
28
|
-
jumpFirst: '
|
|
29
|
-
}
|
|
24
|
+
addSign: 'workflow.add-sign',
|
|
25
|
+
removeSign: 'workflow.remove-sign',
|
|
26
|
+
jump: 'workflow.jump',
|
|
27
|
+
jumpPrevious: 'workflow.jump-previous',
|
|
28
|
+
jumpFirst: 'workflow.jump-first'
|
|
29
|
+
};
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
32
|
* 待办分页列表
|
|
@@ -74,7 +74,7 @@ export async function todoOperate(type, params) {
|
|
|
74
74
|
* @returns
|
|
75
75
|
*/
|
|
76
76
|
export async function getTodoDetail(params) {
|
|
77
|
-
const res = await SohelpHttp.get(`/engine/web/crud/
|
|
77
|
+
const res = await SohelpHttp.get(`/engine/web/crud/getById`, params);
|
|
78
78
|
if (res.meta.success) {
|
|
79
79
|
return res.data;
|
|
80
80
|
}
|
|
@@ -111,7 +111,9 @@ export async function getTasks(params) {
|
|
|
111
111
|
* 已阅
|
|
112
112
|
*/
|
|
113
113
|
export async function readByCc(taskId) {
|
|
114
|
-
const res = await SohelpHttp.post(`/engine/web/workflow/readByCc`, {
|
|
114
|
+
const res = await SohelpHttp.post(`/engine/web/workflow/readByCc`, {
|
|
115
|
+
taskId
|
|
116
|
+
});
|
|
115
117
|
if (res.meta.success) {
|
|
116
118
|
return res.meta.message;
|
|
117
119
|
}
|
package/style/index.scss
ADDED
|
File without changes
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 安全的数学/条件表达式求值器
|
|
3
|
+
* 仅支持:数字运算(+-*/%)、比较(> < >= <= === !== == !=)、逻辑(&& || !)、属性访问(row.field)、字符串
|
|
4
|
+
* 不支持:函数调用、赋值、new、import、require 等危险操作
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// 白名单:只允许标识符、点号、数字、运算符、圆括号、单/双引号字符串、空白、逗号
|
|
8
|
+
// 不允许:方括号[]、反引号`、花括号{}、分号;、反斜杠\(阻止unicode转义)
|
|
9
|
+
const SAFE_EXPR_PATTERN = /^[\w\s.'"$+\-*/%()><=!&|?:,]+$/;
|
|
10
|
+
// 扩展危险关键字检测,涵盖更多绕过手段
|
|
11
|
+
const DANGEROUS_KEYWORDS = /\b(import|require|eval|Function|constructor|prototype|__proto__|window|document|globalThis|process|fetch|XMLHttpRequest|setTimeout|setInterval|alert|confirm|prompt|atob|btoa|escape|unescape|decodeURI|encodeURI|decodeURIComponent|encodeURIComponent|this|self|top|parent|frames|location|navigator|history|screen|chrome|Proxy|Reflect|Symbol|Object|Array|String|Number|Boolean|RegExp|Date|Math|JSON|Promise|Error)\b/;
|
|
12
|
+
// handler 代码的危险关键字(比表达式宽松一些,允许常见的安全对象如 Math/JSON/Array 等)
|
|
13
|
+
const DANGEROUS_CODE_KEYWORDS = /\b(import|require|eval|Function|constructor|prototype|__proto__|window|document|globalThis|process|fetch|XMLHttpRequest|setTimeout|setInterval|alert|confirm|prompt|Proxy|Reflect|self|top|parent|frames|location|navigator|history|screen|chrome)\b/;
|
|
14
|
+
// 检测不安全的字符序列:方括号(属性访问绕过)、反引号(模板字符串)、unicode转义
|
|
15
|
+
const UNSAFE_SEQUENCES = /[\[\]`\\]/;
|
|
16
|
+
|
|
17
|
+
export function isSafeExpression(expr) {
|
|
18
|
+
if (!expr || typeof expr !== 'string') return false;
|
|
19
|
+
// 检测不安全字符序列(方括号、反引号、反斜杠)
|
|
20
|
+
if (UNSAFE_SEQUENCES.test(expr)) return false;
|
|
21
|
+
if (!SAFE_EXPR_PATTERN.test(expr)) return false;
|
|
22
|
+
if (DANGEROUS_KEYWORDS.test(expr)) return false;
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function isSafeCode(code) {
|
|
27
|
+
if (!code || typeof code !== 'string') return false;
|
|
28
|
+
if (DANGEROUS_CODE_KEYWORDS.test(code)) return false;
|
|
29
|
+
// 在 handler 代码中也禁止 unicode 转义和反引号(防止关键字重构绕过)
|
|
30
|
+
if (/\\u[0-9a-fA-F]{4}/.test(code)) return false;
|
|
31
|
+
if (/`/.test(code)) return false;
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 安全求值简单表达式(公式计算、条件判断)
|
|
37
|
+
* @param {string} expr - 表达式字符串,如 "row.price * row.qty"
|
|
38
|
+
* @param {Object} context - 上下文变量,如 { row: { price: 10, qty: 2 } }
|
|
39
|
+
* @returns {*} 计算结果
|
|
40
|
+
* @throws {Error} 如果表达式不安全
|
|
41
|
+
*/
|
|
42
|
+
export function safeEval(expr, context = {}) {
|
|
43
|
+
if (!isSafeExpression(expr)) {
|
|
44
|
+
throw new Error(`不安全的表达式: ${expr}`);
|
|
45
|
+
}
|
|
46
|
+
const keys = Object.keys(context);
|
|
47
|
+
const values = Object.values(context);
|
|
48
|
+
try {
|
|
49
|
+
const func = new Function(...keys, `"use strict"; return (${expr})`);
|
|
50
|
+
return func(...values);
|
|
51
|
+
} catch (e) {
|
|
52
|
+
throw new Error(`表达式执行错误: ${expr} - ${e.message}`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* 安全执行服务端配置的 handler 代码(带沙箱限制,异步)
|
|
58
|
+
* 仅允许访问白名单中的上下文变量
|
|
59
|
+
* @param {string} code - 代码字符串
|
|
60
|
+
* @param {string[]} paramNames - 参数名数组
|
|
61
|
+
* @param {*[]} contextValues - 参数值数组
|
|
62
|
+
* @param {Object} [thisArg] - 可选的 this 上下文
|
|
63
|
+
*/
|
|
64
|
+
export function safeFunctionExec(code, paramNames, contextValues, thisArg) {
|
|
65
|
+
if (!code || typeof code !== 'string') return;
|
|
66
|
+
if (!isSafeCode(code)) {
|
|
67
|
+
console.warn('[安全警告] handler 代码包含危险关键字或不安全序列,已拦截:', code.substring(0, 100));
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const func = new Function(...paramNames, `"use strict"; return (async () => { ${code} })()`);
|
|
71
|
+
return thisArg ? func.call(thisArg, ...contextValues) : func(...contextValues);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* 安全执行服务端配置的代码(带沙箱限制,同步)
|
|
76
|
+
* @param {string} code - 代码字符串
|
|
77
|
+
* @param {string[]} paramNames - 参数名数组
|
|
78
|
+
* @param {*[]} contextValues - 参数值数组
|
|
79
|
+
* @param {Object} [thisArg] - 可选的 this 上下文
|
|
80
|
+
*/
|
|
81
|
+
export function safeFunctionExecSync(code, paramNames, contextValues, thisArg) {
|
|
82
|
+
if (!code || typeof code !== 'string') return;
|
|
83
|
+
if (!isSafeCode(code)) {
|
|
84
|
+
console.warn('[安全警告] handler 代码包含危险关键字或不安全序列,已拦截:', code.substring(0, 100));
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const func = new Function(...paramNames, `"use strict"; return (() => { ${code} })()`);
|
|
88
|
+
return thisArg ? func.call(thisArg, ...contextValues) : func(...contextValues);
|
|
89
|
+
}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 属性
|
|
3
|
-
*/
|
|
4
|
-
export const prop = {
|
|
5
|
-
url: {
|
|
6
|
-
type: String,
|
|
7
|
-
required: true
|
|
8
|
-
},
|
|
9
|
-
|
|
10
|
-
mappingFields: {
|
|
11
|
-
type: Object,
|
|
12
|
-
default: () => {
|
|
13
|
-
return {
|
|
14
|
-
label: 'label',
|
|
15
|
-
value: 'value'
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
},
|
|
19
|
-
|
|
20
|
-
width: {
|
|
21
|
-
type: String,
|
|
22
|
-
default: '200px'
|
|
23
|
-
},
|
|
24
|
-
|
|
25
|
-
placeholder: {
|
|
26
|
-
type: String,
|
|
27
|
-
default: '请选择'
|
|
28
|
-
},
|
|
29
|
-
|
|
30
|
-
modelValue: {
|
|
31
|
-
type: Array || String || Number,
|
|
32
|
-
required: true
|
|
33
|
-
},
|
|
34
|
-
filterable: {
|
|
35
|
-
type: Boolean,
|
|
36
|
-
default: true
|
|
37
|
-
},
|
|
38
|
-
clearable: {
|
|
39
|
-
type: Boolean,
|
|
40
|
-
default: true
|
|
41
|
-
},
|
|
42
|
-
disabled: {
|
|
43
|
-
type: Boolean,
|
|
44
|
-
default: false
|
|
45
|
-
},
|
|
46
|
-
size: {
|
|
47
|
-
type: String,
|
|
48
|
-
validator: function (value) {
|
|
49
|
-
return ['large', 'default', 'small', ''].includes(value);
|
|
50
|
-
},
|
|
51
|
-
default: 'default'
|
|
52
|
-
},
|
|
53
|
-
multiple: {
|
|
54
|
-
type: Boolean,
|
|
55
|
-
default: false
|
|
56
|
-
},
|
|
57
|
-
type: {
|
|
58
|
-
type: String,
|
|
59
|
-
default: 'select'
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* 事件
|
|
65
|
-
*/
|
|
66
|
-
|
|
67
|
-
export const emit = ['update:modelValue', 'change'];
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="sohelp-user-select">
|
|
3
|
-
<sohelp-dyn-select
|
|
4
|
-
v-bind="$attrs"
|
|
5
|
-
:url="url"
|
|
6
|
-
:labelField="labelField"
|
|
7
|
-
:valueField="valueField"
|
|
8
|
-
:readonly="readonly"
|
|
9
|
-
:datasource="datasource"
|
|
10
|
-
v-model="modelValue"
|
|
11
|
-
></sohelp-dyn-select>
|
|
12
|
-
</div>
|
|
13
|
-
</template>
|
|
14
|
-
<script setup>
|
|
15
|
-
import SohelpDynSelect from "../sohelp-dyn-select/index.vue";
|
|
16
|
-
|
|
17
|
-
const modelValue = defineModel("modelValue", { type: [String, Number, Array], default: "" });
|
|
18
|
-
|
|
19
|
-
const props = defineProps({
|
|
20
|
-
datasource: {
|
|
21
|
-
type: [Array, Function, Promise],
|
|
22
|
-
required: true
|
|
23
|
-
},
|
|
24
|
-
url: {
|
|
25
|
-
type: String,
|
|
26
|
-
default: "/engine/web/user/list"
|
|
27
|
-
},
|
|
28
|
-
labelField: {
|
|
29
|
-
type: String,
|
|
30
|
-
default: "user_name"
|
|
31
|
-
},
|
|
32
|
-
valueField: {
|
|
33
|
-
type: String,
|
|
34
|
-
default: "id"
|
|
35
|
-
},
|
|
36
|
-
readonly: {
|
|
37
|
-
type: Boolean,
|
|
38
|
-
default: false
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
console.error(exposedMethods)
|
|
42
|
-
// 暴露子组件特有方法
|
|
43
|
-
defineExpose({
|
|
44
|
-
...exposedMethods
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
</script>
|
|
48
|
-
<script>
|
|
49
|
-
export default {
|
|
50
|
-
name: "SohelpUserSelect"
|
|
51
|
-
};
|
|
52
|
-
</script>
|
|
53
|
-
<style></style>
|