tiny-vue/examples/sites/demos/pc/app/flowchart/basic-usage-composition-api...

331 lines
9.2 KiB
Vue

<template>
<div class="tiny-demo">
<button @click="toggleStatus">切换状态</button>
<tiny-flowchart
ref="chartRef"
:data="chartData"
:config="chartConfig"
@click-node="onClickNode"
@click-link="onClickLink"
@click-blank="onClickBlank"
>
<template #content="params">
<handler-list class="custom-handler-list" :params="params" />
</template>
</tiny-flowchart>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { Modal, Popover } from '@opentiny/vue'
import Flowchart from '@opentiny/vue-flowchart'
import { hooks } from '@opentiny/vue-common'
import { iconYes, iconPanelMini, iconChevronDown, iconChevronUp } from '@opentiny/vue-icon'
const { createNode, createLink, createItem, createConfig } = Flowchart
const HandlerDropdown = {
template: `<div class="tiny-handler-dropdown">
<div v-for="(handler, i) in params.node.info.items" :key="i" class="tiny-handler-dropdown-item">
<div class="item-icon">
<div :style="iconStyle(handler)">
<tiny-icon-yes v-if="check(handler)"></tiny-icon-yes>
<tiny-icon-pane v-else></tiny-icon-pane>
</div>
</div>
<div class="item-status">{{ handler.status }}</div>
<div class="item-head">
<img :src="params.allItem[handler.key]" :style="imgStyle" />
</div>
<div class="item-name">{{ handler.name }}</div>
<div class="item-key">{{ handler.key }}</div>
<div class="item-role">{{ handler.role }}</div>
<div class="item-date">{{ handler.date }}</div>
</div>
</div>`,
name: 'TinyHandlerDropdown',
components: {
TinyIconYes: iconYes(),
TinyIconPane: iconPanelMini()
},
props: {
params: Object
},
computed: {
imgStyle() {
return 'width:16px;height:16px;border-radius:50%;'
}
},
methods: {
check(handler) {
const { params } = this
return typeof params.config.checkItemStatus === 'function' && params.config.checkItemStatus(handler)
},
iconStyle(handler) {
const color = this.check(handler)
? 'border-color:#52c41a;background:#52c41a;'
: 'border-color:#40a9ff;background:#40a9ff;'
return (
this.imgStyle +
'display:flex;align-items:center;justify-content:center;' +
'border-width:1px;border-style:solid;' +
color
)
}
}
}
const HandlerList = {
template: `<tiny-popover
placement="bottom-start"
title=""
v-model="params.showPop"
width="220"
trigger="manual"
popper-class="demo-popover-class1"
:visible-arrow="false"
>
<handler-dropdown class="custom-handler-dropdown" :params="params" />
<template #reference>
<div
class="tiny-handler-list"
:class="'name-' + params.node.name"
:style="'border:1px solid ' + params.config.listBorderColor"
>
<div class="tiny-handler-list__heads" :style="'width:' + headWidth + 'px'">
<img
v-for="(item, i) in heads"
class="tiny-handler-list__head-img"
:key="i"
:src="item.head"
:style="item.style"
/>
</div>
<div
class="tiny-handler-list__icon"
:style="'width:' + params.config.listIconSize + 'px;fill:' + params.config.listIconColor"
@click="toggleStatus"
>
<tiny-icon-up v-if="params.dropdowns[params.node.name]"></tiny-icon-up>
<tiny-icon-down v-else></tiny-icon-down>
</div>
</div>
</template>
</tiny-popover>`,
name: 'TinyHandlerList',
components: {
TinyIconDown: iconChevronDown(),
TinyIconUp: iconChevronUp(),
HandlerDropdown,
TinyPopover: Popover
},
props: {
params: Object
},
computed: {
headWidth() {
const { params } = this
return params.config.listWidth - 6 - params.config.listIconSize
},
heads() {
const { params, headWidth } = this
const { allItem, node, config } = params
const { headSize } = config
const { info } = node
const { items } = info
const imgStyle = `width:${headSize}px;height:${headSize}px`
const res = []
items.map(({ key }, i) => {
let left
if (items.length > 1) {
left = Math.floor(((headWidth - headSize) / (items.length - 1)) * i)
} else if (items.length === 1) {
left = Math.floor(headWidth / 2)
}
const style = `${imgStyle};left:${left}px`
res.push({ head: allItem[key], style })
})
return res
}
},
methods: {
toggleStatus() {
const { params } = this
params.dropdowns[params.node.name] = !params.dropdowns[params.node.name]
}
}
}
const handlers = [
createItem('WX100001', '张三', '转审人', '已转审', '很好', '2018-08-20 12:00', ''),
createItem('WX100002', '李四', '主管', '已转审', '非常好', '2018-08-20 12:00', ''),
createItem('WX100003', '王五', '主管', '处理中', '', '', '')
]
const chartData = {
nodes: [
createNode('1', 1, '基础信息', '2018.08.02', [], 1, 0),
createNode('2', 1, '调职补偿', '2018.08.02', handlers, 0, 2),
createNode('3', 1, '汇总调职补偿', '', [], 1, 4),
createNode('4', 3, '启动精算', '', [], 4, 5),
createNode('5', 3, '复核精算', '', [], 4, 6),
createNode('6', 3, '审核精算', '', [], 4, 7),
createNode('7', 1, '调职补偿', '2018.08.02', [], 2, 1),
createNode('8', 1, '复核', '2018.08.02', [], 2, 2),
createNode('9', 2, '审批', '2018.08.02', [], 2, 3),
createNode('10', 1, '复核', '2018.08.02', [], 4, 2),
createNode('11', 2, '审批', '2018.08.02', [], 4, 3),
createNode('12', 3, '运算调职兑现率', '', [], 4, 4),
createNode('13', 1, '复核', '2018.08.02', [], 6, 2),
createNode('14', 4, '审批审批审批审批审批0123456789asdfghjkl', '2018.08.02', [], 6, 3)
],
links: [
createLink('1', '2', '0 r0.5 t1 c r1.5', 1),
createLink('2', '3', '0 r1.5 c b1 r0.5', 3),
createLink('3', '4', '0 r0.5 c b3 r0.5', 3),
createLink('4', '5', '', 3),
createLink('5', '6', '', 3),
createLink('1', '7', 'r0.5 b1 c r0.5', 1),
createLink('7', '8', '', 1),
createLink('8', '9', '', 1),
createLink('9', '3', '0 r0.5 c t1', 3),
createLink('10', '11', '', 1),
createLink('11', '12', '', 3),
createLink('12', '4', '0 r0.5', 3),
createLink('13', '14', '', 1),
createLink('14', '4', '0 r1.5 c t2', 3, 'dash')
]
}
const chartConfig = createConfig()
chartConfig.headUrl = `${import.meta.env.VITE_APP_BUILD_BASE_URL}static/images/mountain.png`
chartConfig.checkItemStatus = (item) => ~['已转审', '已同意'].indexOf(item.status)
chartConfig.adjustPos = (afterNode) => afterNode.raw.name === '2' && (afterNode.y += 1)
const nodeFail = chartData.nodes[chartData.nodes.length - 1]
const linkDash = chartData.links[chartData.links.length - 1]
const flag = ref(false)
const chartRef = ref()
const TinyFlowchart = Flowchart
function toggleStatus() {
flag.value = !flag.value
// 1.更改数据
nodeFail.info.status = flag.value ? 1 : 4
linkDash.info.style = flag.value ? 'solid' : 'dash'
linkDash.info.status = flag.value ? 1 : 3
chartConfig.anchor = flag.value ? 'left' : 'center'
// 2.刷新流程图
chartRef.value.refresh()
}
function onClickNode(afterNode, e) {
Modal.message('click-node')
}
function onClickLink(afterLink, e) {
Modal.message('click-link')
}
function onClickBlank(param, e) {
Modal.message('click-blank')
}
</script>
<style>
/* HandlerList */
.tiny-handler-list {
width: calc(100% - 2px);
height: 100%;
border-radius: 3px;
position: relative;
}
.tiny-handler-list__heads {
position: absolute;
top: 1px;
left: 1px;
height: calc(100% - 2px);
}
.tiny-handler-list__icon {
position: absolute;
top: 1px;
right: 1px;
height: calc(100% - 2px);
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
}
.tiny-handler-list__head-img {
border-radius: 50%;
position: absolute;
}
/* HandlerDropdown */
.tiny-handler-dropdown {
width: auto;
height: auto;
padding: 6px;
text-align: initial;
cursor: pointer;
}
.tiny-handler-dropdown-item + .tiny-handler-dropdown-item {
margin-top: 6px;
padding-top: 6px;
border-top: 1px dashed #999;
}
.tiny-handler-dropdown-item {
font-size: 12px;
display: grid;
gap: 4px;
grid-template-rows: repeat(3, 20px);
grid-template-columns: 20px 20px 40px auto 40px;
grid-template-areas:
'icon status status status status'
'. head name key role'
'. date date date date';
align-items: center;
justify-content: start;
}
.tiny-handler-dropdown-item .item-icon {
grid-area: icon;
}
.tiny-handler-dropdown-item .item-status {
grid-area: status;
font-weight: bold;
}
.tiny-handler-dropdown-item .item-head {
grid-area: head;
}
.tiny-handler-dropdown-item .item-name {
grid-area: name;
}
.tiny-handler-dropdown-item .item-key {
grid-area: key;
}
.tiny-handler-dropdown-item .item-role {
grid-area: role;
background: #d9d9d9;
}
.tiny-handler-dropdown-item .item-date {
grid-area: date;
color: #999;
}
.tiny-handler-dropdown-item .item-icon .tiny-svg {
fill: #fff;
}
.tiny-popover.demo-popover-class1.tiny-popper[x-placement^='bottom'] {
margin-top: 2px;
padding: 0;
}
</style>