widget.qw 0.0.2 → 1.0.1
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/build/style.css +101 -0
- package/build/widget.qw.es.js +612 -206
- package/build/widget.qw.umd.js +612 -206
- package/package.json +1 -1
- package/src/api/index.js +16 -0
- package/src/components/CascaderPicker.vue +107 -0
- package/src/components/CascaderPop.vue +313 -0
- package/src/components/index.js +10 -0
- package/src/router/index.ts +10 -0
- package/src/util/tree_util.js +34 -0
- package/src/views/cascaderpicker/index.vue +86 -0
- package/src/views/cascaderpop/index.vue +91 -0
- package/src/views/home/index.vue +2 -0
- package/vite.config.ts +2 -2
package/package.json
CHANGED
package/src/api/index.js
CHANGED
|
@@ -123,4 +123,20 @@ export const auth_get_user_info = (data) => {
|
|
|
123
123
|
method: "POST",
|
|
124
124
|
data: data,
|
|
125
125
|
})
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export const part_children = (data) => {
|
|
129
|
+
return request_json({
|
|
130
|
+
url: vm.urlCallback() + "/ac-api/part/children",
|
|
131
|
+
method: "POST",
|
|
132
|
+
data: data,
|
|
133
|
+
})
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export const part_detail = (data) => {
|
|
137
|
+
return request_json({
|
|
138
|
+
url: vm.urlCallback() + "/ac-api/part/detail",
|
|
139
|
+
method: "POST",
|
|
140
|
+
data: data,
|
|
141
|
+
})
|
|
126
142
|
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<van-field v-if="!isGone" :label="props.label" :required="isRequired" :rules="props.rules" :disabled="isDisabled"
|
|
3
|
+
:placeholder="props.placeholder" :is-link="isReadonly ? false : true" @click="data.isShowPop = !isReadonly"
|
|
4
|
+
label-class="label">
|
|
5
|
+
<template #input>
|
|
6
|
+
<van-tag class="selected-node" v-if="modelValue" :closeable="!isDisabled" type="primary" size="medium"
|
|
7
|
+
@close.stop="onDelete">
|
|
8
|
+
{{ data.selectedNode.formatLabel }}
|
|
9
|
+
</van-tag>
|
|
10
|
+
</template>
|
|
11
|
+
</van-field>
|
|
12
|
+
|
|
13
|
+
<CascaderPop v-model:show="data.isShowPop"
|
|
14
|
+
v-model="modelValue"
|
|
15
|
+
:placeholder="props.placeholder"
|
|
16
|
+
@select="onSelect" :queryNodes="props.queryNodes" :queryNode="props.queryNode" />
|
|
17
|
+
|
|
18
|
+
</template>
|
|
19
|
+
<script setup>
|
|
20
|
+
import { reactive, onMounted, watch } from "vue";
|
|
21
|
+
import util from "@/util"
|
|
22
|
+
import { useVModel } from '@vueuse/core'
|
|
23
|
+
import CascaderPop from './CascaderPop.vue'
|
|
24
|
+
|
|
25
|
+
const props = defineProps({
|
|
26
|
+
modelValue: {
|
|
27
|
+
type: String,
|
|
28
|
+
default: '',
|
|
29
|
+
},
|
|
30
|
+
label: {
|
|
31
|
+
type: String,
|
|
32
|
+
default: "",
|
|
33
|
+
},
|
|
34
|
+
placeholder: {
|
|
35
|
+
type: String,
|
|
36
|
+
default: "",
|
|
37
|
+
},
|
|
38
|
+
required: {
|
|
39
|
+
type: Boolean,
|
|
40
|
+
default: false,
|
|
41
|
+
},
|
|
42
|
+
readonly: {
|
|
43
|
+
type: Boolean,
|
|
44
|
+
default: false,
|
|
45
|
+
},
|
|
46
|
+
rules: {
|
|
47
|
+
type: Array,
|
|
48
|
+
default: [],
|
|
49
|
+
},
|
|
50
|
+
auth: {
|
|
51
|
+
type: String,
|
|
52
|
+
default: "",
|
|
53
|
+
},
|
|
54
|
+
queryNodes:{
|
|
55
|
+
type:Function,
|
|
56
|
+
default:()=>{}
|
|
57
|
+
},
|
|
58
|
+
queryNode:{
|
|
59
|
+
type:Function,
|
|
60
|
+
default:()=>{}
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// 弹出层
|
|
65
|
+
const data = reactive({
|
|
66
|
+
isShowPop: false,
|
|
67
|
+
selectedNode: {}
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
// 定义emit
|
|
71
|
+
const emit = defineEmits(["update:modelValue", "select"]);
|
|
72
|
+
const modelValue = useVModel(props, 'modelValue', emit)
|
|
73
|
+
const { isRequired, isReadonly, isGone, isDisabled } = util.props2auth(props);
|
|
74
|
+
|
|
75
|
+
//首页加载
|
|
76
|
+
onMounted(() => {
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
const onSelect = (node) => {
|
|
80
|
+
data.selectedNode = node
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const onDelete=()=>{
|
|
84
|
+
data.selectedNode={}
|
|
85
|
+
modelValue.value = null
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
watch(() => modelValue.value, async (n, o) => {
|
|
89
|
+
if (!n) {
|
|
90
|
+
data.selectedNode = {}
|
|
91
|
+
return
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
props.queryNode((node)=>{
|
|
95
|
+
data.selectedNode = node
|
|
96
|
+
emit('select', data.selectedNode)
|
|
97
|
+
})
|
|
98
|
+
}, {
|
|
99
|
+
immediate: true
|
|
100
|
+
})
|
|
101
|
+
</script>
|
|
102
|
+
|
|
103
|
+
<style scoped>
|
|
104
|
+
.user{
|
|
105
|
+
padding:4px 8px;
|
|
106
|
+
}
|
|
107
|
+
</style>
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<van-popup v-model:show="show" round position="bottom" class="cascader-pop">
|
|
3
|
+
<div class="cascader-selector">
|
|
4
|
+
<div class="cascader-header">
|
|
5
|
+
<div class="header-left">
|
|
6
|
+
<van-button @click="onBack" icon="arrow-left" size="small" />
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
<!-- 移除header-center包装,直接使用current-path -->
|
|
10
|
+
<div class="current-path">{{ pathsLabel }}</div>
|
|
11
|
+
|
|
12
|
+
<div class="header-right">
|
|
13
|
+
<van-button size="small" @click="onCancel" class="cancel-btn">取消</van-button>
|
|
14
|
+
|
|
15
|
+
<van-button type="primary" size="small" @click="onSubmit" class="confirm-btn">确定</van-button>
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<!-- 搜索框 -->
|
|
20
|
+
<van-search v-model="data.keyword" :placeholder="props.placeholder" @clear="onClear" @search="onSearch"
|
|
21
|
+
@cancel="onClear" show-action>
|
|
22
|
+
<template #action>
|
|
23
|
+
<div @click="onSearch">搜索</div>
|
|
24
|
+
</template>
|
|
25
|
+
</van-search>
|
|
26
|
+
|
|
27
|
+
<div class="scroll-container">
|
|
28
|
+
<!-- 遍历子节点列表 -->
|
|
29
|
+
<van-cell-group>
|
|
30
|
+
<van-cell v-for="(item, i) in optionNodes" :key="i" >
|
|
31
|
+
<template #title>
|
|
32
|
+
<div class="cell-content">
|
|
33
|
+
<div class="circle-selector" @click.stop="onToggle(item)">
|
|
34
|
+
<van-icon v-if="data.selectedNodeId === item.id" name="success" size="20" color="#409eff"/>
|
|
35
|
+
<van-icon v-if="data.selectedNodeId != item.id" name="circle" size="20" color="#e0e0e0"/>
|
|
36
|
+
</div>
|
|
37
|
+
<span class="name">{{ item.label }}</span>
|
|
38
|
+
</div>
|
|
39
|
+
</template>
|
|
40
|
+
<template #right-icon v-if="item.hasChildren" >
|
|
41
|
+
<van-icon name="arrow" @click.stop="onNextLevel(item)"/>
|
|
42
|
+
</template>
|
|
43
|
+
</van-cell>
|
|
44
|
+
</van-cell-group>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
</van-popup>
|
|
48
|
+
</template>
|
|
49
|
+
|
|
50
|
+
<script setup>
|
|
51
|
+
import { ref, onMounted, watch, reactive, computed } from "vue";
|
|
52
|
+
import util from "@/util"
|
|
53
|
+
import { useVModel } from '@vueuse/core'
|
|
54
|
+
|
|
55
|
+
const props = defineProps({
|
|
56
|
+
modelValue: {
|
|
57
|
+
type: String,
|
|
58
|
+
default: ''
|
|
59
|
+
},
|
|
60
|
+
show: {
|
|
61
|
+
type: Boolean,
|
|
62
|
+
default: false,
|
|
63
|
+
},
|
|
64
|
+
placeholder: {
|
|
65
|
+
type: String,
|
|
66
|
+
default: ''
|
|
67
|
+
},
|
|
68
|
+
queryNodes: {
|
|
69
|
+
type: Function,
|
|
70
|
+
default: () => { }
|
|
71
|
+
},
|
|
72
|
+
queryNode: {
|
|
73
|
+
type: Function,
|
|
74
|
+
default: () => { }
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
// 定义emit
|
|
78
|
+
const emit = defineEmits(["update:show", "select"]);
|
|
79
|
+
// 弹出?
|
|
80
|
+
const show = useVModel(props, 'show', emit)
|
|
81
|
+
const modelValue = useVModel(props, 'modelValue', emit)
|
|
82
|
+
const data = reactive({
|
|
83
|
+
// 所有节点
|
|
84
|
+
totalNodes: [],
|
|
85
|
+
// 搜索关键字
|
|
86
|
+
keyword: "",
|
|
87
|
+
//关键字搜索到的节点列表
|
|
88
|
+
searchNodes: [],
|
|
89
|
+
//当前节点
|
|
90
|
+
currentNode: null,
|
|
91
|
+
//勾选的节点id
|
|
92
|
+
selectedNodeId: ''
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
// 待选节点列表
|
|
96
|
+
const optionNodes = computed(() => {
|
|
97
|
+
if (data.keyword)
|
|
98
|
+
return data.searchNodes
|
|
99
|
+
else if (data.currentNode)
|
|
100
|
+
return data.currentNode?.children ? data.currentNode.children : []
|
|
101
|
+
else
|
|
102
|
+
return data.totalNodes ? data.totalNodes : []
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
//选中节点的路径:父/子/孙
|
|
106
|
+
const pathsLabel = computed(() => {
|
|
107
|
+
if (!data.currentNode || !data.currentNode.id)
|
|
108
|
+
return ''
|
|
109
|
+
|
|
110
|
+
let paths = util.findPaths(data.currentNode.id, data.totalNodes)
|
|
111
|
+
console.log("paths", paths);
|
|
112
|
+
let res = paths.map(item => item.label).join('/')
|
|
113
|
+
return res
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
// 查询树状节点列表
|
|
117
|
+
const queryTotalNodes = async () => {
|
|
118
|
+
await props.queryNodes({keyword:data.keyword,parentId:''}, (nodes) => {
|
|
119
|
+
data.totalNodes = nodes
|
|
120
|
+
})
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// 关键字查询
|
|
124
|
+
const onSearch = async () => {
|
|
125
|
+
await util.queryNodes({keyword:data.keyword,parentId:''}, (nodes) => {
|
|
126
|
+
data.searchNodes = nodes
|
|
127
|
+
})
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// 返回上一级
|
|
131
|
+
const onBack = () => {
|
|
132
|
+
if (!data.currentNode || !data.currentNode.id)
|
|
133
|
+
return
|
|
134
|
+
|
|
135
|
+
data.keyword = ""
|
|
136
|
+
data.currentNode = util.findParent(data.currentNode.id, data.totalNodes)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const onClear=()=>{
|
|
140
|
+
data.keyword = ''
|
|
141
|
+
data.searchNodes = []
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// 清除掉选中节点
|
|
145
|
+
const reset = () => {
|
|
146
|
+
// 当前节点
|
|
147
|
+
data.currentNode = null
|
|
148
|
+
// 搜索关键字
|
|
149
|
+
data.keyword = ""
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// 确认按钮
|
|
153
|
+
const onSubmit = () => {
|
|
154
|
+
if (!data.selectedNodeId) {
|
|
155
|
+
util.warnToast("请选择")
|
|
156
|
+
return
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
let selectedNode = util.findNode(data.selectedNodeId, data.totalNodes)
|
|
160
|
+
modelValue.value = selectedNode.id
|
|
161
|
+
emit('select', selectedNode)
|
|
162
|
+
show.value = false
|
|
163
|
+
|
|
164
|
+
reset()
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// 取消按钮
|
|
168
|
+
const onCancel = () => {
|
|
169
|
+
show.value = false
|
|
170
|
+
reset()
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const onToggle = (node) => {
|
|
174
|
+
if(data.selectedNodeId == node.id)
|
|
175
|
+
data.selectedNodeId = ''
|
|
176
|
+
else
|
|
177
|
+
data.selectedNodeId = node.id
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const onNextLevel = (node) => {
|
|
181
|
+
props.queryNodes({ keyword: data.keyword, parentId: node.id }, (nodes) => {
|
|
182
|
+
node.children = nodes
|
|
183
|
+
data.currentNode = node
|
|
184
|
+
})
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
//首页加载
|
|
188
|
+
onMounted(async () => {
|
|
189
|
+
await queryTotalNodes()
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
watch(() => props.modelValue, () => {
|
|
193
|
+
// 初始化当前节点
|
|
194
|
+
data.currentNode = util.findParent(props.modelValue, data.totalNodes)
|
|
195
|
+
}, { immediate: true })
|
|
196
|
+
</script>
|
|
197
|
+
|
|
198
|
+
<style scoped>
|
|
199
|
+
.cascader-pop {
|
|
200
|
+
width: 100%;
|
|
201
|
+
overflow: hidden;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.cascader-selector {
|
|
205
|
+
padding: 10px;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
.search-buttons {
|
|
209
|
+
display: flex;
|
|
210
|
+
gap: 10px;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.clear-btn {
|
|
214
|
+
background-color: #f2f3f5;
|
|
215
|
+
border: none;
|
|
216
|
+
border-radius: 4px;
|
|
217
|
+
padding: 4px 8px;
|
|
218
|
+
font-size: 14px;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.confirm-btn {
|
|
222
|
+
background-color: #1989fa;
|
|
223
|
+
color: white;
|
|
224
|
+
border: none;
|
|
225
|
+
border-radius: 4px;
|
|
226
|
+
padding: 4px 8px;
|
|
227
|
+
font-size: 14px;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.no-results {
|
|
231
|
+
text-align: center;
|
|
232
|
+
padding: 20px;
|
|
233
|
+
color: #969799;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
.cascader-header {
|
|
237
|
+
padding: 10px;
|
|
238
|
+
border-bottom: 1px solid #ebedf0;
|
|
239
|
+
display: flex;
|
|
240
|
+
justify-content: space-between;
|
|
241
|
+
align-items: center;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.current-path {
|
|
245
|
+
flex: 1;
|
|
246
|
+
font-size: 14px;
|
|
247
|
+
color: #323233;
|
|
248
|
+
white-space: nowrap;
|
|
249
|
+
overflow: hidden;
|
|
250
|
+
text-overflow: ellipsis;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.header-right {
|
|
254
|
+
display: flex;
|
|
255
|
+
gap: 8px;
|
|
256
|
+
margin-left: auto;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.cancel-btn {
|
|
260
|
+
color: #969799;
|
|
261
|
+
margin-right: 5px;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
.scroll-container {
|
|
265
|
+
height: calc(80vh - 150px);
|
|
266
|
+
overflow-y: auto;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
.cell-content {
|
|
271
|
+
display: flex;
|
|
272
|
+
align-items: center;
|
|
273
|
+
gap: 12px;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
.circle-selector {
|
|
277
|
+
width: 20px;
|
|
278
|
+
height: 20px;
|
|
279
|
+
border-radius: 50%;
|
|
280
|
+
display: flex;
|
|
281
|
+
align-items: center;
|
|
282
|
+
justify-content: center;
|
|
283
|
+
transition: all 0.2s;
|
|
284
|
+
flex-shrink: 0;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.circle-selector.selected {
|
|
288
|
+
background-color: #1989fa;
|
|
289
|
+
border-color: #1989fa;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.circle-selector.selected .van-icon {
|
|
293
|
+
color: white;
|
|
294
|
+
font-size: 14px;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
.van-cell__right-icon {
|
|
298
|
+
color: #969799;
|
|
299
|
+
font-size: 16px;
|
|
300
|
+
margin-left: 8px;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.name {
|
|
304
|
+
flex: 1;
|
|
305
|
+
overflow: hidden;
|
|
306
|
+
text-overflow: ellipsis;
|
|
307
|
+
white-space: nowrap;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
.cancel-btn {
|
|
311
|
+
color: #969799;
|
|
312
|
+
}
|
|
313
|
+
</style>
|
package/src/components/index.js
CHANGED
|
@@ -27,6 +27,8 @@ import ProjectDropdown from "./ProjectDropdown.vue";
|
|
|
27
27
|
import Switch from './Switch.vue'
|
|
28
28
|
import Sheet from './Sheet.vue'
|
|
29
29
|
import TreePicker from './TreePicker.vue'
|
|
30
|
+
import CascaderPop from './CascaderPop.vue'
|
|
31
|
+
import CascaderPicker from './CascaderPicker.vue'
|
|
30
32
|
|
|
31
33
|
const components = [
|
|
32
34
|
{
|
|
@@ -136,6 +138,14 @@ const components = [
|
|
|
136
138
|
{
|
|
137
139
|
name: 'WidgetQwTreePicker',
|
|
138
140
|
widget: TreePicker
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
name: 'WidgetQwCascaderPop',
|
|
144
|
+
widget: CascaderPop
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
name: 'WidgetQwCascaderPicker',
|
|
148
|
+
widget: CascaderPicker
|
|
139
149
|
}
|
|
140
150
|
];
|
|
141
151
|
// 导出组件
|
package/src/router/index.ts
CHANGED
|
@@ -149,6 +149,16 @@ const routes: Array<RouteRecordRaw> = [
|
|
|
149
149
|
path: "/treepicker",
|
|
150
150
|
name: "treepicker",
|
|
151
151
|
component: () => import("../views/treepicker/index.vue"),
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
path: "/cascaderpop",
|
|
155
|
+
name: "cascaderpop",
|
|
156
|
+
component: () => import("../views/cascaderpop/index.vue"),
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
path: "/cascaderpicker",
|
|
160
|
+
name: "cascaderpicker",
|
|
161
|
+
component: () => import("../views/cascaderpicker/index.vue"),
|
|
152
162
|
}
|
|
153
163
|
];
|
|
154
164
|
|
package/src/util/tree_util.js
CHANGED
|
@@ -41,6 +41,40 @@ export const findNode = (id, nodes) => {
|
|
|
41
41
|
return res[res.length - 1]
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
// 查找节点路径列表
|
|
45
|
+
// 返回:[父,子,孙]
|
|
46
|
+
export const findPaths =(targetId, nodes, path = [])=> {
|
|
47
|
+
if (!nodes || nodes.length < 1 || !targetId)
|
|
48
|
+
return []
|
|
49
|
+
|
|
50
|
+
for (const node of nodes) {
|
|
51
|
+
if (node.id === targetId) {
|
|
52
|
+
return [...path, node];
|
|
53
|
+
}
|
|
54
|
+
if (node.children?.length) {
|
|
55
|
+
const founds = findPaths(targetId, node.children, [...path, node]);
|
|
56
|
+
if (founds && founds.length > 0) return founds;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return []
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
//查找父节点
|
|
64
|
+
export const findParent = (id, nodes) => {
|
|
65
|
+
if (!nodes || !id) {
|
|
66
|
+
return null
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
let paths = findPaths(id, nodes)
|
|
70
|
+
|
|
71
|
+
if (!paths || paths.length < 2) {
|
|
72
|
+
return null
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return paths[paths.length-2]
|
|
76
|
+
}
|
|
77
|
+
|
|
44
78
|
// id列表转为节点对象列表
|
|
45
79
|
export const ids2nodes=(ids,totalNodes)=>{
|
|
46
80
|
if(!totalNodes || totalNodes.length<1 || !ids || ids.length<1)
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="page">
|
|
3
|
+
<widget-qw-cascader-picker v-model="data.id" label="零件" placeholder="请选择零件"
|
|
4
|
+
:queryNodes="queryNodes"
|
|
5
|
+
:queryNode="queryNode"
|
|
6
|
+
:auth="data.auth" />
|
|
7
|
+
</div>
|
|
8
|
+
</template>
|
|
9
|
+
|
|
10
|
+
<script setup>
|
|
11
|
+
import { onMounted, reactive, watch } from "vue";
|
|
12
|
+
import util from '@/util'
|
|
13
|
+
|
|
14
|
+
const data = reactive({
|
|
15
|
+
auth: 'require',
|
|
16
|
+
id: '',
|
|
17
|
+
projectId:'GnsMl3mO'
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
const queryNodes = async (params,setNodes) => {
|
|
21
|
+
if (!data.projectId)
|
|
22
|
+
return
|
|
23
|
+
|
|
24
|
+
let p = {
|
|
25
|
+
projectId: data.projectId,
|
|
26
|
+
hasChildren: false
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if(params.keyword)
|
|
30
|
+
p.keyword = params.keyword
|
|
31
|
+
|
|
32
|
+
if(params.parentId)
|
|
33
|
+
p.parentId = params.parentId
|
|
34
|
+
|
|
35
|
+
let res = await util.part_children(p)
|
|
36
|
+
if (res.code != 200)
|
|
37
|
+
return
|
|
38
|
+
|
|
39
|
+
let formatNodes = res.data.map(item=>{
|
|
40
|
+
return {
|
|
41
|
+
id:item.id,
|
|
42
|
+
label: item.formatName,
|
|
43
|
+
formatLabel: item.path,
|
|
44
|
+
hasChildren: item.hasChildren,
|
|
45
|
+
data: item
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
setNodes(formatNodes)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const queryNode=async(setNode)=>{
|
|
52
|
+
let params={
|
|
53
|
+
id:data.id
|
|
54
|
+
}
|
|
55
|
+
let res = await util.part_detail(params)
|
|
56
|
+
if(res.code!=200)
|
|
57
|
+
return
|
|
58
|
+
|
|
59
|
+
let formatNode = {
|
|
60
|
+
id:res.data.id,
|
|
61
|
+
label: res.data.formatName,
|
|
62
|
+
formatLabel: item.path,
|
|
63
|
+
hasChildren: res.data.hasChildren,
|
|
64
|
+
data:res.data
|
|
65
|
+
}
|
|
66
|
+
setNode(formatNode)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
watch(() => data.id, (newVal, oldVal) => {
|
|
70
|
+
console.log(newVal, oldVal)
|
|
71
|
+
})
|
|
72
|
+
</script>
|
|
73
|
+
|
|
74
|
+
<style lang="scss" scoped>
|
|
75
|
+
.page {
|
|
76
|
+
height: 100vh;
|
|
77
|
+
background: #fff;
|
|
78
|
+
text-align: center;
|
|
79
|
+
background-size: cover;
|
|
80
|
+
display: flex;
|
|
81
|
+
flex-direction: column;
|
|
82
|
+
justify-content: flex-start;
|
|
83
|
+
padding: 80px 15px 0 15px;
|
|
84
|
+
box-sizing: border-box;
|
|
85
|
+
}
|
|
86
|
+
</style>
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="page">
|
|
3
|
+
<van-button @click="data.isShow=true">弹出</van-button>
|
|
4
|
+
<widget-qw-cascader-pop v-model="data.id" v-model:show="data.isShow"
|
|
5
|
+
label="零件" placeholder="请选择零件"
|
|
6
|
+
:queryNodes="queryNodes" :queryNode="queryNode" @select="onSelect" />
|
|
7
|
+
</div>
|
|
8
|
+
</template>
|
|
9
|
+
|
|
10
|
+
<script setup>
|
|
11
|
+
import { onMounted, reactive, watch } from "vue";
|
|
12
|
+
import util from '@/util'
|
|
13
|
+
|
|
14
|
+
const data = reactive({
|
|
15
|
+
auth: 'require',
|
|
16
|
+
id: '',
|
|
17
|
+
isShow: false,
|
|
18
|
+
projectId: 'GnsMl3mO'
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
const queryNodes = async (params, setNodes) => {
|
|
22
|
+
if (!data.projectId)
|
|
23
|
+
return
|
|
24
|
+
|
|
25
|
+
let p = {
|
|
26
|
+
projectId: data.projectId,
|
|
27
|
+
hasChildren: false
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (params.keyword)
|
|
31
|
+
p.keyword = params.keyword
|
|
32
|
+
|
|
33
|
+
if (params.parentId)
|
|
34
|
+
p.parentId = params.parentId
|
|
35
|
+
|
|
36
|
+
let res = await util.part_children(p)
|
|
37
|
+
if (res.code != 200)
|
|
38
|
+
return
|
|
39
|
+
|
|
40
|
+
let formatNodes = res.data.map(item => {
|
|
41
|
+
return {
|
|
42
|
+
id: item.id,
|
|
43
|
+
label: item.formatName,
|
|
44
|
+
formatLabel: item.path,
|
|
45
|
+
hasChildren: item.hasChildren,
|
|
46
|
+
data: item
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
setNodes(formatNodes)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const queryNode = async (setNode) => {
|
|
53
|
+
let params = {
|
|
54
|
+
id: data.id
|
|
55
|
+
}
|
|
56
|
+
let res = await util.part_detail(params)
|
|
57
|
+
if (res.code != 200)
|
|
58
|
+
return
|
|
59
|
+
|
|
60
|
+
let formatNode = {
|
|
61
|
+
id: res.data.id,
|
|
62
|
+
label: res.data.formatName,
|
|
63
|
+
formatLabel: item.path,
|
|
64
|
+
hasChildren: res.data.hasChildren,
|
|
65
|
+
data: res.data
|
|
66
|
+
}
|
|
67
|
+
setNode(formatNode)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const onSelect=(node)=>{
|
|
71
|
+
console.log('onSelect',node)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
watch(() => data.id, (newVal, oldVal) => {
|
|
75
|
+
console.log(newVal, oldVal)
|
|
76
|
+
})
|
|
77
|
+
</script>
|
|
78
|
+
|
|
79
|
+
<style lang="scss" scoped>
|
|
80
|
+
.page {
|
|
81
|
+
height: 100vh;
|
|
82
|
+
background: #fff;
|
|
83
|
+
text-align: center;
|
|
84
|
+
background-size: cover;
|
|
85
|
+
display: flex;
|
|
86
|
+
flex-direction: column;
|
|
87
|
+
justify-content: flex-start;
|
|
88
|
+
padding: 80px 15px 0 15px;
|
|
89
|
+
box-sizing: border-box;
|
|
90
|
+
}
|
|
91
|
+
</style>
|