Skip to content

Commit 2227234

Browse files
Create MetaListItemOp.vue
1 parent 7877046 commit 2227234

1 file changed

Lines changed: 386 additions & 0 deletions

File tree

Lines changed: 386 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,386 @@
1+
<template>
2+
<div
3+
:class="['item-content', { 'active-item': currentIndex === index }]"
4+
@click="openEdit"
5+
>
6+
<div class="option-input">
7+
<div class="left">
8+
<icon-more class="tiny-svg-size icon-more"></icon-more>
9+
<slot
10+
name="content"
11+
:data="item"
12+
></slot>
13+
</div>
14+
<div class="right">
15+
<slot
16+
name="operate"
17+
:data="item"
18+
>
19+
<template
20+
v-for="item in dataScource.btnList"
21+
:key="item.type"
22+
>
23+
<template v-if="item.type === 'edit' && !itemData.option?.builtIn">
24+
<tiny-popover
25+
:key="itemData.index"
26+
v-model="isVisible"
27+
placement="bottom-start"
28+
:popper-class="['option-popper', { 'fixed-left': expand }]"
29+
:visible-arrow="!expand"
30+
width="295"
31+
height="auto"
32+
trigger="manual"
33+
@hide="hide(item)"
34+
>
35+
<template v-if="isVisible">
36+
<div
37+
ref="addOptions"
38+
class="add-options"
39+
:style="`left:${itemData.left}px;top:${itemData.top}px`"
40+
>
41+
<icon-close
42+
class="tiny-svg-size icon-close"
43+
@click="closeEditOption"
44+
></icon-close>
45+
<slot name="metaForm">
46+
<meta-form
47+
v-bind="itemData"
48+
footerbtnHide="true"
49+
@changeItem="change"
50+
@cancel="cancel"
51+
@confirm="formConfirm"
52+
></meta-form>
53+
</slot>
54+
<slot name="footer"></slot></div
55+
></template>
56+
57+
<template #reference>
58+
<component
59+
:is="item.icon"
60+
class="tiny-svg-size icon-edit"
61+
@click="btnClick($event, item.type)"
62+
></component>
63+
</template>
64+
</tiny-popover>
65+
</template>
66+
<template v-if="item.type === 'show' || item.type === 'hide'">
67+
<template v-if="item.type === 'show' && itemData.option.itemVisible === false">
68+
<tiny-tooltip
69+
class="item"
70+
effect="dark"
71+
:content="item.title"
72+
:open-delay="500"
73+
placement="top"
74+
@click="btnClick($event, item.type)"
75+
>
76+
<span class="item-icon">
77+
<component :is="item.icon"></component>
78+
</span>
79+
</tiny-tooltip>
80+
</template>
81+
<template
82+
v-if="
83+
item.type === 'hide' && (itemData.option.itemVisible || itemData.option.itemVisible === undefined)
84+
"
85+
>
86+
<tiny-tooltip
87+
class="item"
88+
effect="dark"
89+
:content="item.title"
90+
:open-delay="500"
91+
placement="top"
92+
@click="btnClick($event, item.type)"
93+
>
94+
<span class="item-icon">
95+
<component
96+
:is="item.icon"
97+
@click="closeEditOption"
98+
></component>
99+
</span>
100+
</tiny-tooltip>
101+
</template>
102+
</template>
103+
<template v-if="item.type === 'delete' && !itemData.option?.builtIn">
104+
<span
105+
class="item-icon"
106+
@click="btnClick($event, item.type)"
107+
>
108+
<component :is="item.icon"></component>
109+
</span>
110+
</template>
111+
</template>
112+
</slot>
113+
</div>
114+
</div>
115+
</div>
116+
<!-- 删除页面弹窗 -->
117+
<tiny-dialog-box
118+
v-if="isShow"
119+
:append-to-body="true"
120+
:visible="isShow"
121+
title="提示"
122+
width="20%"
123+
@update:visible="isShow = $event"
124+
>
125+
<span class="switch-tip">
126+
<span>确定删除吗?</span>
127+
</span>
128+
<template #footer>
129+
<tiny-button @click="isShow = false">取消</tiny-button>
130+
<tiny-button
131+
type="danger"
132+
@click="confirm"
133+
>删除</tiny-button
134+
>
135+
</template>
136+
</tiny-dialog-box>
137+
<!-- 遮罩层 -->
138+
<mask-modal
139+
:visible="showMask && !expand"
140+
@close="closeMask"
141+
></mask-modal>
142+
</template>
143+
144+
<script>
145+
import { reactive, watchEffect, ref, onMounted } from 'vue';
146+
import { Tooltip, Input, FormItem, Form, Popover, DialogBox, Button } from '@opentiny/vue';
147+
import { iconDel, iconMore, iconClose } from '@opentiny/vue-icon';
148+
import { MaskModal, MetaForm } from '@opentiny/tiny-engine-common';
149+
150+
export default {
151+
components: {
152+
TinyTooltip: Tooltip,
153+
TinyInput: Input,
154+
TinyFormItem: FormItem,
155+
TinyForm: Form,
156+
TinyPopover: Popover,
157+
TinyDialogBox: DialogBox,
158+
TinyButton: Button,
159+
MetaForm,
160+
MaskModal,
161+
IconDel: iconDel(),
162+
IconMore: iconMore(),
163+
IconClose: iconClose(),
164+
},
165+
inheritAttrs: false,
166+
props: {
167+
item: {
168+
type: Object,
169+
default: () => {},
170+
},
171+
dataScource: {
172+
type: Object,
173+
default: () => {},
174+
},
175+
index: {
176+
type: Number,
177+
default: 0,
178+
},
179+
currentIndex: {
180+
type: Number,
181+
default: -1,
182+
},
183+
// 使用itemClick判断是否由双击触发弹出面板
184+
itemClick: {
185+
type: Boolean,
186+
default: false,
187+
},
188+
// 子级弹出层是否在左侧展开
189+
expand: {
190+
type: Boolean,
191+
default: false,
192+
},
193+
},
194+
emits: ['editItem', 'changeItem', 'deleteItem', 'hide', 'hideItem', 'showItem'],
195+
setup(props, { emit }) {
196+
const itemData = reactive({});
197+
const isShow = ref(false);
198+
const isVisible = ref(false);
199+
const showMask = ref(false);
200+
let top = ref(0);
201+
202+
const deleteItem = () => {
203+
isShow.value = true;
204+
};
205+
206+
const editList = () => {
207+
showMask.value = true;
208+
isVisible.value = true;
209+
};
210+
211+
const btnClick = ($event, action) => {
212+
switch (action) {
213+
case 'delete':
214+
deleteItem();
215+
break;
216+
case 'show':
217+
emit('showItem', { index: props.index });
218+
break;
219+
case 'hide':
220+
emit('hideItem', { index: props.index });
221+
break;
222+
case 'openModal':
223+
emit('editItem', { action: 'openModal', index: props.index });
224+
break;
225+
case 'edit':
226+
emit('editItem', { action: 'edit', index: props.index });
227+
editList();
228+
break;
229+
default:
230+
emit('editItem', { index: props.index });
231+
editList();
232+
break;
233+
}
234+
};
235+
236+
const change = () => {
237+
emit('changeItem', itemData);
238+
};
239+
240+
const confirm = () => {
241+
isShow.value = false;
242+
243+
emit('deleteItem', itemData);
244+
};
245+
246+
const closeEditOption = () => {
247+
emit('closeItem');
248+
isVisible.value = false;
249+
showMask.value = false;
250+
};
251+
252+
const hide = () => {
253+
emit('hide');
254+
};
255+
256+
const isShowModal = ref(false);
257+
258+
const cancel = () => {
259+
isVisible.value = false;
260+
};
261+
262+
const formConfirm = (formData) => {
263+
emit('changeItem', { data: formData, index: props.index });
264+
isVisible.value = false;
265+
};
266+
267+
watchEffect(() => {
268+
itemData.option = props.item;
269+
itemData.textField = props.dataScource.textField;
270+
itemData.valueField = props.dataScource.valueField;
271+
itemData.label = props.dataScource.label;
272+
itemData.index = props.index;
273+
if (props.currentIndex !== props.index) {
274+
cancel();
275+
}
276+
});
277+
278+
const openEdit = () => {
279+
if (props.itemClick && !isShow.value) {
280+
editList();
281+
}
282+
};
283+
284+
const closeMask = () => {
285+
showMask.value = false;
286+
isVisible.value = false;
287+
};
288+
289+
onMounted(() => {
290+
if (props.currentIndex === props.index) {
291+
editList();
292+
}
293+
});
294+
295+
return {
296+
itemData,
297+
change,
298+
deleteItem,
299+
closeEditOption,
300+
btnClick,
301+
hide,
302+
isShow,
303+
confirm,
304+
editList,
305+
isVisible,
306+
showMask,
307+
closeMask,
308+
top,
309+
isShowModal,
310+
formConfirm,
311+
cancel,
312+
openEdit,
313+
};
314+
},
315+
};
316+
</script>
317+
318+
<style lang="less" scoped>
319+
.item-content {
320+
border: 1px solid var(--te-component-common-border-color-divider);
321+
border-left: none;
322+
border-right: none;
323+
background: var(--te-component-common-bg-color);
324+
margin-bottom: -1px;
325+
color: var(--te-component-common-text-color-primary);
326+
&.active-item {
327+
background-color: var(--te-component-meta-list-item-bg-color);
328+
}
329+
.option-input {
330+
display: flex;
331+
height: 24px;
332+
align-items: center;
333+
padding: 2px;
334+
& > div {
335+
overflow: hidden;
336+
.tiny-svg {
337+
margin-right: 5px;
338+
font-size: 12px;
339+
opacity: 0.4;
340+
color: var(--te-component-common-text-color-primary);
341+
&:hover {
342+
cursor: pointer;
343+
opacity: 1;
344+
}
345+
}
346+
347+
&.left {
348+
flex: 1;
349+
display: flex;
350+
align-items: center;
351+
.icon-more {
352+
font-size: 14px;
353+
flex-shrink: 0;
354+
cursor: move;
355+
}
356+
:deep(span) {
357+
white-space: nowrap;
358+
overflow: hidden;
359+
text-overflow: ellipsis;
360+
}
361+
}
362+
&.right {
363+
float: left;
364+
text-align: right;
365+
margin-right: 8px;
366+
}
367+
}
368+
}
369+
}
370+
371+
.tiny-popover {
372+
position: relative;
373+
.icon-close {
374+
position: absolute;
375+
top: 6px;
376+
right: 10px;
377+
}
378+
}
379+
.add-options {
380+
overflow-y: auto;
381+
max-height: calc(100vh - 94px); // 94为头部高度和底部高度
382+
&.top {
383+
margin-bottom: 0;
384+
}
385+
}
386+
</style>

0 commit comments

Comments
 (0)