fix base
@ -0,0 +1 @@
|
||||
<svg t="1731390087280" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4297" width="200" height="200"><path d="M639.9 541.7c76.4-44.2 127.9-126.8 127.9-221.5C767.7 179 653.2 64.5 512 64.5S256.3 179 256.3 320.2c0 89.6 46.1 168.4 115.8 214.1C193.5 593 64.5 761.2 64.5 959.5h63.9c0-211.5 172.1-383.6 383.6-383.6 44.9 0 87.8 8.1 127.9 22.4v-56.6zM320.2 320.2c0-105.8 86-191.8 191.8-191.8s191.8 86 191.8 191.8S617.7 512 512 512s-191.8-86-191.8-191.8zM831.6 767.7V639.9h-63.9v127.8H639.9v63.9h127.8v127.9h63.9V831.6h127.9v-63.9z" fill="#5f6266" p-id="4298"></path></svg>
|
||||
|
After Width: | Height: | Size: 608 B |
|
After Width: | Height: | Size: 10 KiB |
@ -0,0 +1 @@
|
||||
<svg t="1729561718271" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8640" width="200" height="200"><path d="M908.5952 920.4224H164.7616a31.0784 31.0784 0 0 1-30.976-30.976c0-17.0496 13.9264-30.976 30.976-30.976h743.8336c17.0496 0 31.0272 13.9264 31.0272 30.976a31.0784 31.0784 0 0 1-31.0272 30.976z m0-123.9552H164.7616a31.0784 31.0784 0 0 1-30.976-30.976v-154.9824c0-51.1488 41.8304-92.9792 92.9792-92.9792h198.3488c-6.1952-37.1712-24.7808-72.8064-51.1488-103.8336a216.576 216.576 0 0 1-54.2208-144.128c0-58.88 23.2448-114.688 66.6112-156.4672C429.7728 71.168 485.5296 51.0976 545.9968 52.6848c111.5648 4.608 206.08 100.6592 207.616 212.2752 1.536 55.808-20.1216 110.0288-57.344 151.8592-26.3168 27.904-41.8304 61.952-48.0256 100.7104h198.3488c51.2 0 93.0304 41.8304 93.0304 92.9792v154.9824a31.0784 31.0784 0 0 1-31.0272 30.976z m-712.8064-61.952H877.568v-124.0064a31.0784 31.0784 0 0 0-31.0272-30.976h-232.448a31.0784 31.0784 0 0 1-30.976-31.0272c0-65.024 23.2448-127.0784 66.6624-173.568 27.8528-29.3888 41.8304-68.1472 41.8304-108.4416-1.536-80.5888-68.1984-148.7872-148.7872-151.8592a150.528 150.528 0 0 0-113.152 43.3664 153.6 153.6 0 0 0-48.0256 111.616c0 37.1712 13.9776 74.3424 38.7584 102.2464 44.9536 51.1488 69.7344 113.152 69.7344 176.64a31.0784 31.0784 0 0 1-30.976 31.0272h-232.448a31.0784 31.0784 0 0 0-30.976 30.976v123.9552z" fill="#fff" p-id="8641"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@ -0,0 +1 @@
|
||||
<svg t="1729585232424" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1602" width="200" height="200"><path d="M925.5 898.9H804.9c-19 0-34.5-15.4-34.5-34.4V761.3c0-19 15.4-34.4 34.5-34.4h34.5V572.2c0-19-15.4-34.4-34.5-34.4H529.2V727h34.5c19 0 34.5 15.4 34.5 34.4v103.2c0 19-15.4 34.4-34.5 34.4H443.1c-19 0-34.5-15.4-34.5-34.4V761.3c0-19 15.4-34.4 34.5-34.4h34.5V537.8H219.1c-19 0-34.5 15.4-34.5 34.4V727h34.5c19 0 34.5 15.4 34.5 34.4v103.2c0 19-15.4 34.4-34.5 34.4H98.5c-19 0-34.5-15.4-34.5-34.4V761.3c0-19 15.4-34.4 34.5-34.4H133V555c0-38 30.9-68.8 68.9-68.8h275.7V297.1h-34.5c-19 0-34.5-15.4-34.5-34.4V159.5c0-19 15.4-34.4 34.5-34.4h120.6c19 0 34.5 15.4 34.5 34.4v103.2c0 19-15.4 34.4-34.5 34.4h-34.5v189.2h292.9c38.1 0 68.9 30.8 68.9 68.8v172h34.5c19 0 34.5 15.4 34.5 34.4v103.2c0 18.8-15.4 34.2-34.5 34.2z m0 0" p-id="1603" fill="#fff"></path></svg>
|
||||
|
After Width: | Height: | Size: 897 B |
@ -0,0 +1 @@
|
||||
<svg t="1729649333541" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1644" width="200" height="200"><path d="M647.888 893.84L491.904 571.52l393.888-393.888-237.904 716.208zM872.32 123.232L459.872 535.68 134.96 380.88 872.32 123.232z m90.72-68.32a23.968 23.968 0 0 0-24.784-5.568L64.08 354.816a23.984 23.984 0 0 0-2.4 44.32l381.392 181.728 187.36 387.088a24.048 24.048 0 0 0 23.152 13.504 24.032 24.032 0 0 0 21.232-16.4L968.96 79.552c2.88-8.672 0.592-18.24-5.92-24.64z" fill="#fff" p-id="1645"></path></svg>
|
||||
|
After Width: | Height: | Size: 553 B |
@ -0,0 +1 @@
|
||||
<svg t="1730189225011" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2651" id="mx_n_1730189225011" width="200" height="200"><path d="M793.889347 200.380242c27.648573 20.615681 42.196018 32.710677 63.781037 56.119312 25.313864 27.453234 43.242957 48.52047 64.502857 86.507991 44.537416 79.580127 53.527718 136.949077 53.517684 212.063821 0 64.933675-15.452562 130.459388-40.138263 187.311893-22.076044 50.841799-61.545336 104.359483-101.886297 138.933914-45.506755 39.001681-81.214423 60.462941-137.605337 81.826531-55.699867 21.102023-114.070267 28.641326-181.379458 27.791064-68.274516-0.862973-129.364283-11.040029-180.533878-31.80489-46.159002-18.731189-98.338744-46.827973-141.596418-87.541551-43.946046-41.361142-70.369064-75.958317-93.88139-127.198155-26.157437-57.004361-40.094111-129.065922-39.680686-191.781288 0-36.980719 4.033895-70.902234 12.252873-105.241856 8.532726-35.651474 20.069131-69.572989 38.13135-102.35257 18.856956-34.221214 36.754607-62.067803 58.869452-88.973149 23.248751-28.285434 39.2104-46.417894 64.295476-63.475987 18.297696-12.442861 36.879036-9.295353 47.199252-2.306612 4.403836 2.982273 8.919391 6.577992 12.933218 12.933217 9.572307 15.156208-0.334486 29.769212-6.69038 38.465836-7.148625 9.781026-23.130343 26.023643-38.738775 43.218205-38.192895 42.075603-55.133918 65.965228-74.986303 106.965794-30.772668 63.552249-37.495827 115.718611-38.131349 166.573791-0.668971 53.517684 9.995096 99.647251 27.427813 140.483919 33.916163 80.572211 94.807915 144.44289 175.270414 178.615938 41.108271 17.845472 113.812713 37.319888 181.960793 38.13135 56.193568 0.668971 125.919751-11.321666 166.574459-28.096784 45.935566-18.954626 97.223569-56.862539 127.10383-94.324918 23.013273-28.852721 52.179742-70.910931 64.413884-105.694749 14.863868-42.260239 24.806784-87.661297 24.559934-132.458943 0-54.414105-11.53373-108.417461-36.918505-156.856317-20.16747-38.483228-46.480777-74.607665-84.66899-108.048189-13.377414-11.714352-23.822728-20.067124-38.808348-31.619586-10.191774-7.857065-36.059546-25.027545-28.923632-47.326356 4.970455-15.53217 18.303717-25.294464 31.887843-27.205046 19.456354-2.736092 28.565733 2.427027 43.705885 12.041479l6.179955 4.322891zM510.755379 531.65738c-8.696624-0.668971-10.034566-0.446204-20.738102-6.689711-11.031333-6.434832-17.839451-21.183637-16.514219-35.175166V92.220334c0-18.178619 0.386665-22.815926 8.988295-31.685813 5.351768-5.519011 10.963097-11.381873 26.08987-11.539751 16.055305-0.167243 21.407073 3.846584 27.929542 9.700081 9.70677 8.711341 10.703537 17.56049 10.377078 33.525483v397.5715c-0.509756 15.273947 0.326458 22.967114-11.380535 33.502739-3.884046 3.495374-8.027653 7.693167-20.96087 8.362138l-3.791059 0.000669z m4.453341 0.573308" p-id="2652" fill="#ffffff"></path></svg>
|
||||
|
After Width: | Height: | Size: 2.7 KiB |
@ -0,0 +1 @@
|
||||
<svg t="1729585239190" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1755" width="200" height="200"><path d="M901.489435 536.822664v-0.931601l-1.001722-198.240726c-0.100172-19.162936-9.21584-37.474409-25.043042-50.246361-14.024104-11.349507-32.265456-17.60025-51.348255-17.610268l-618.062295-0.18031c-19.142902 0-37.424323 6.280795-51.478478 17.690405-15.827203 12.842072-24.902802 31.2437-24.892785 50.486775v196.798247A114.987635 114.987635 0 1 0 195.295664 536.922836V338.782282c1.15198-1.252152 4.808264-3.596181 10.768509-3.596181l276.725622 0.090155v199.753326a114.987635 114.987635 0 1 0 65.612772 1.412428V335.326342l275.693849 0.080138c6.01033 0 9.626546 2.344029 10.768508 3.596181l1.001722 195.70637a114.987635 114.987635 0 1 0 65.592737 2.113633zM214.979496 645.910158a56.437001 56.437001 0 1 1-56.437001-56.437001 56.507122 56.507122 0 0 1 56.437001 56.437001z m354.689623 0a56.437001 56.437001 0 1 1-56.437001-56.437001 56.507122 56.507122 0 0 1 56.437001 56.437001z m295.507904 56.437001a56.437001 56.437001 0 1 1 56.437001-56.437001 56.507122 56.507122 0 0 1-56.457035 56.437001z" p-id="1756" fill='#fff'></path></svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
@ -0,0 +1 @@
|
||||
<svg width="22" height="22" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path fill="#FAFAFA" d="M0 0h22v22H0z"/><circle fill="#919BAE" cx="1" cy="1" r="1"/></g></svg>
|
||||
|
After Width: | Height: | Size: 192 B |
@ -0,0 +1 @@
|
||||
<svg t="1729561814171" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1359" width="200" height="200"><path d="M674.496 603.456c120.256 0 218.176 90.752 221.44 203.84l0.064 5.888v125.888c0 11.52-9.92 20.928-22.144 20.928h-44.352a21.568 21.568 0 0 1-22.144-20.928v-125.888c0-67.712-56.512-123.264-128-125.76l-4.928-0.064H349.568c-71.488 0-130.176 53.504-132.864 121.152l-0.064 4.672v125.888c0 11.52-9.92 20.928-22.144 20.928h-44.352A21.568 21.568 0 0 1 128 939.072v-125.888c0-113.92 95.872-206.528 215.36-209.664l6.208-0.064h324.928zM497.216 128c122.368 0 221.568 93.888 221.568 209.728s-99.2 209.792-221.568 209.792c-122.304 0-221.44-93.952-221.44-209.728C275.712 221.952 374.848 128 497.152 128z m0 83.904c-73.408 0-132.864 56.32-132.864 125.888 0 69.504 59.52 125.824 132.864 125.824 73.408 0 132.928-56.32 132.928-125.824 0-69.504-59.52-125.888-132.928-125.888z" fill="#fff" p-id="1360"></path></svg>
|
||||
|
After Width: | Height: | Size: 947 B |
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1724297262365" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1396" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M707.91 103c16.28 0 29.522 13.007 29.897 29.195l0.009 0.706v111.878a29.96 29.96 0 0 1-0.898 7.3l171.177-0.001c16.28 0 29.522 13.007 29.897 29.195l0.008 0.706v637.12c0 16.278-13.01 29.518-29.2 29.893l-0.705 0.008H270.884c-16.28 0-29.522-13.007-29.897-29.195l-0.008-0.706V787.274c0-16.514 13.389-29.9 29.905-29.9 16.28 0 29.522 13.007 29.897 29.194l0.008 0.706v101.924h577.4V311.88h-577.4v88.787c0 16.278-13.009 29.518-29.2 29.893l-0.705 0.008c-16.28 0-29.522-13.008-29.897-29.195l-0.008-0.706V281.979c0-16.278 13.009-29.518 29.2-29.893l0.705-0.008h408.019a29.916 29.916 0 0 1-0.89-6.593l-0.008-0.706v-81.978H132.808v407.113h385.787L408.223 456.982c-11.36-11.624-11.329-30.143-0.066-41.729l0.554-0.555c11.625-11.358 30.147-11.327 41.734-0.066l0.555 0.554 161.028 164.762c11.244 11.504 11.344 29.793 0.362 41.42l-0.55 0.565-161.027 161.849c-11.648 11.707-30.583 11.757-42.292 0.11-11.524-11.461-11.754-29.979-0.657-41.723l0.546-0.563 111.319-111.89H102.905c-16.28 0-29.522-13.007-29.897-29.195l-0.008-0.705V132.9c0-16.278 13.01-29.518 29.2-29.893l0.705-0.008H707.91z" p-id="1397"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@ -0,0 +1,96 @@
|
||||
import {ComponentStyle, DiyComponent} from '@/components/DiyEditor/util'
|
||||
|
||||
/** 积分商城属性 */
|
||||
export interface PromotionPointProperty {
|
||||
// 布局类型:单列 | 三列
|
||||
layoutType: 'oneColBigImg' | 'oneColSmallImg' | 'twoCol'
|
||||
// 商品字段
|
||||
fields: {
|
||||
// 商品名称
|
||||
name: PromotionPointFieldProperty
|
||||
// 商品简介
|
||||
introduction: PromotionPointFieldProperty
|
||||
// 商品价格
|
||||
price: PromotionPointFieldProperty
|
||||
// 市场价
|
||||
marketPrice: PromotionPointFieldProperty
|
||||
// 商品销量
|
||||
salesCount: PromotionPointFieldProperty
|
||||
// 商品库存
|
||||
stock: PromotionPointFieldProperty
|
||||
}
|
||||
// 角标
|
||||
badge: {
|
||||
// 是否显示
|
||||
show: boolean
|
||||
// 角标图片
|
||||
imgUrl: string
|
||||
}
|
||||
// 按钮
|
||||
btnBuy: {
|
||||
// 类型:文字 | 图片
|
||||
type: 'text' | 'img'
|
||||
// 文字
|
||||
text: string
|
||||
// 文字按钮:背景渐变起始颜色
|
||||
bgBeginColor: string
|
||||
// 文字按钮:背景渐变结束颜色
|
||||
bgEndColor: string
|
||||
// 图片按钮:图片地址
|
||||
imgUrl: string
|
||||
}
|
||||
// 上圆角
|
||||
borderRadiusTop: number
|
||||
// 下圆角
|
||||
borderRadiusBottom: number
|
||||
// 间距
|
||||
space: number
|
||||
// 秒杀活动编号
|
||||
activityIds: number[]
|
||||
// 组件样式
|
||||
style: ComponentStyle
|
||||
}
|
||||
|
||||
// 商品字段
|
||||
export interface PromotionPointFieldProperty {
|
||||
// 是否显示
|
||||
show: boolean
|
||||
// 颜色
|
||||
color: string
|
||||
}
|
||||
|
||||
// 定义组件
|
||||
export const component = {
|
||||
id: 'PromotionPoint',
|
||||
name: '积分商城',
|
||||
icon: 'ep:present',
|
||||
property: {
|
||||
layoutType: 'oneColBigImg',
|
||||
fields: {
|
||||
name: { show: true, color: '#000' },
|
||||
introduction: { show: true, color: '#999' },
|
||||
price: { show: true, color: '#ff3000' },
|
||||
marketPrice: { show: true, color: '#c4c4c4' },
|
||||
salesCount: { show: true, color: '#c4c4c4' },
|
||||
stock: { show: false, color: '#c4c4c4' }
|
||||
},
|
||||
badge: { show: false, imgUrl: '' },
|
||||
btnBuy: {
|
||||
type: 'text',
|
||||
text: '立即兑换',
|
||||
bgBeginColor: '#FF6000',
|
||||
bgEndColor: '#FE832A',
|
||||
imgUrl: ''
|
||||
},
|
||||
borderRadiusTop: 8,
|
||||
borderRadiusBottom: 8,
|
||||
space: 8,
|
||||
style: {
|
||||
bgType: 'color',
|
||||
bgColor: '',
|
||||
marginLeft: 8,
|
||||
marginRight: 8,
|
||||
marginBottom: 8
|
||||
} as ComponentStyle
|
||||
}
|
||||
} as DiyComponent<PromotionPointProperty>
|
||||
@ -0,0 +1,204 @@
|
||||
<template>
|
||||
<div ref="contentRef" class="markdown-view" v-html="renderedMarkdown"></div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useClipboard } from '@vueuse/core'
|
||||
import MarkdownIt from 'markdown-it'
|
||||
import 'highlight.js/styles/vs2015.min.css'
|
||||
import hljs from 'highlight.js'
|
||||
|
||||
// 定义组件属性
|
||||
const props = defineProps({
|
||||
content: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
|
||||
const message = useMessage() // 消息弹窗
|
||||
const { copy } = useClipboard() // 初始化 copy 到粘贴板
|
||||
const contentRef = ref()
|
||||
|
||||
const md = new MarkdownIt({
|
||||
highlight: function (str, lang) {
|
||||
if (lang && hljs.getLanguage(lang)) {
|
||||
try {
|
||||
const copyHtml = `<div id="copy" data-copy='${str}' style="position: absolute; right: 10px; top: 5px; color: #fff;cursor: pointer;">复制</div>`
|
||||
return `<pre style="position: relative;">${copyHtml}<code class="hljs">${hljs.highlight(lang, str, true).value}</code></pre>`
|
||||
} catch (__) {}
|
||||
}
|
||||
return ``
|
||||
}
|
||||
})
|
||||
|
||||
/** 渲染 markdown */
|
||||
const renderedMarkdown = computed(() => {
|
||||
return md.render(props.content)
|
||||
})
|
||||
|
||||
/** 初始化 **/
|
||||
onMounted(async () => {
|
||||
// 添加 copy 监听
|
||||
contentRef.value.addEventListener('click', (e: any) => {
|
||||
if (e.target.id === 'copy') {
|
||||
copy(e.target?.dataset?.copy)
|
||||
message.success('复制成功!')
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.markdown-view {
|
||||
font-family: PingFang SC;
|
||||
font-size: 0.95rem;
|
||||
font-weight: 400;
|
||||
line-height: 1.6rem;
|
||||
letter-spacing: 0em;
|
||||
text-align: left;
|
||||
color: #3b3e55;
|
||||
max-width: 100%;
|
||||
|
||||
pre {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
pre code.hljs {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
code.hljs {
|
||||
border-radius: 6px;
|
||||
padding-top: 20px;
|
||||
width: auto;
|
||||
@media screen and (min-width: 1536px) {
|
||||
width: 960px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1536px) and (min-width: 1024px) {
|
||||
width: calc(100vw - 400px - 64px - 32px * 2);
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1024px) and (min-width: 768px) {
|
||||
width: calc(100vw - 32px * 2);
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
width: calc(100vw - 16px * 2);
|
||||
}
|
||||
}
|
||||
|
||||
p,
|
||||
code.hljs {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
p {
|
||||
//margin-bottom: 1rem !important;
|
||||
margin: 0;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
/* 标题通用格式 */
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
color: var(--color-G900);
|
||||
margin: 24px 0 8px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 22px;
|
||||
line-height: 32px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 20px;
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 18px;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 16px;
|
||||
line-height: 26px;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
/* 列表(有序,无序) */
|
||||
ul,
|
||||
ol {
|
||||
margin: 0 0 8px 0;
|
||||
padding: 0;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
color: #3b3e55; // var(--color-CG600);
|
||||
}
|
||||
|
||||
li {
|
||||
margin: 4px 0 0 20px;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
ol > li {
|
||||
list-style-type: decimal;
|
||||
margin-bottom: 1rem;
|
||||
// 表达式,修复有序列表序号展示不全的问题
|
||||
// &:nth-child(n + 10) {
|
||||
// margin-left: 30px;
|
||||
// }
|
||||
|
||||
// &:nth-child(n + 100) {
|
||||
// margin-left: 30px;
|
||||
// }
|
||||
}
|
||||
|
||||
ul > li {
|
||||
list-style-type: disc;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
margin-right: 11px;
|
||||
margin-bottom: 1rem;
|
||||
color: #3b3e55; // var(--color-G900);
|
||||
}
|
||||
|
||||
ol ul,
|
||||
ol ul > li,
|
||||
ul ul,
|
||||
ul ul li {
|
||||
// list-style: circle;
|
||||
font-size: 16px;
|
||||
list-style: none;
|
||||
margin-left: 6px;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
ul ul ul,
|
||||
ul ul ul li,
|
||||
ol ol,
|
||||
ol ol > li,
|
||||
ol ul ul,
|
||||
ol ul ul > li,
|
||||
ul ol,
|
||||
ul ol > li {
|
||||
list-style: square;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,237 +0,0 @@
|
||||
/* stylelint-disable order/properties-order */
|
||||
<template>
|
||||
<div class="add-node-btn-box">
|
||||
<div class="add-node-btn">
|
||||
<el-popover placement="right-start" v-model="visible" width="auto">
|
||||
<div class="add-node-popover-body">
|
||||
<a class="add-node-popover-item approver" @click="addType(1)">
|
||||
<div class="item-wrapper">
|
||||
<span class="iconfont"></span>
|
||||
</div>
|
||||
<p>审批人</p>
|
||||
</a>
|
||||
<a class="add-node-popover-item notifier" @click="addType(2)">
|
||||
<div class="item-wrapper">
|
||||
<span class="iconfont"></span>
|
||||
</div>
|
||||
<p>抄送人</p>
|
||||
</a>
|
||||
<a class="add-node-popover-item condition" @click="addType(4)">
|
||||
<div class="item-wrapper">
|
||||
<span class="iconfont"></span>
|
||||
</div>
|
||||
<p>条件分支</p>
|
||||
</a>
|
||||
</div>
|
||||
<template #reference>
|
||||
<button class="btn" type="button">
|
||||
<span class="iconfont"></span>
|
||||
</button>
|
||||
</template>
|
||||
</el-popover>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
let props = defineProps({
|
||||
childNodeP: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
})
|
||||
let emits = defineEmits(['update:childNodeP'])
|
||||
let visible = ref(false)
|
||||
const addType = (type) => {
|
||||
visible.value = false
|
||||
if (type != 4) {
|
||||
var data
|
||||
if (type == 1) {
|
||||
data = {
|
||||
nodeName: '审核人',
|
||||
error: true,
|
||||
type: 1,
|
||||
settype: 1,
|
||||
selectMode: 0,
|
||||
selectRange: 0,
|
||||
directorLevel: 1,
|
||||
examineMode: 1,
|
||||
noHanderAction: 1,
|
||||
examineEndDirectorLevel: 0,
|
||||
childNode: props.childNodeP,
|
||||
nodeUserList: []
|
||||
}
|
||||
} else if (type == 2) {
|
||||
data = {
|
||||
nodeName: '抄送人',
|
||||
type: 2,
|
||||
ccSelfSelectFlag: 1,
|
||||
childNode: props.childNodeP,
|
||||
nodeUserList: []
|
||||
}
|
||||
}
|
||||
emits('update:childNodeP', data)
|
||||
} else {
|
||||
emits('update:childNodeP', {
|
||||
nodeName: '路由',
|
||||
type: 4,
|
||||
childNode: null,
|
||||
conditionNodes: [
|
||||
{
|
||||
nodeName: '条件1',
|
||||
error: true,
|
||||
type: 3,
|
||||
priorityLevel: 1,
|
||||
conditionList: [],
|
||||
nodeUserList: [],
|
||||
childNode: props.childNodeP
|
||||
},
|
||||
{
|
||||
nodeName: '条件2',
|
||||
type: 3,
|
||||
priorityLevel: 2,
|
||||
conditionList: [],
|
||||
nodeUserList: [],
|
||||
childNode: null
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.add-node-btn-box {
|
||||
width: 240px;
|
||||
display: inline-flex;
|
||||
-ms-flex-negative: 0;
|
||||
flex-shrink: 0;
|
||||
-webkit-box-flex: 1;
|
||||
-ms-flex-positive: 1;
|
||||
position: relative;
|
||||
|
||||
&:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: -1;
|
||||
margin: auto;
|
||||
width: 2px;
|
||||
height: 100%;
|
||||
background-color: #cacaca;
|
||||
}
|
||||
|
||||
.add-node-btn {
|
||||
user-select: none;
|
||||
width: 240px;
|
||||
padding: 20px 0 32px;
|
||||
display: flex;
|
||||
-webkit-box-pack: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
-webkit-box-flex: 1;
|
||||
flex-grow: 1;
|
||||
|
||||
.btn {
|
||||
outline: none;
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.1);
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
background: #3296fa;
|
||||
border-radius: 50%;
|
||||
position: relative;
|
||||
border: none;
|
||||
line-height: 30px;
|
||||
-webkit-transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
|
||||
.iconfont {
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.3);
|
||||
box-shadow: 0 13px 27px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: none;
|
||||
background: #1e83e9;
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.add-node-popover-body {
|
||||
display: flex;
|
||||
|
||||
.add-node-popover-item {
|
||||
margin-right: 10px;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
flex: 1;
|
||||
color: #191f25 !important;
|
||||
|
||||
.item-wrapper {
|
||||
user-select: none;
|
||||
display: inline-block;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
margin-bottom: 5px;
|
||||
background: #fff;
|
||||
border: 1px solid #e2e2e2;
|
||||
border-radius: 50%;
|
||||
transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
|
||||
.iconfont {
|
||||
font-size: 35px;
|
||||
line-height: 80px;
|
||||
}
|
||||
}
|
||||
|
||||
&.approver {
|
||||
.item-wrapper {
|
||||
color: #ff943e;
|
||||
}
|
||||
}
|
||||
|
||||
&.notifier {
|
||||
.item-wrapper {
|
||||
color: #3296fa;
|
||||
}
|
||||
}
|
||||
|
||||
&.condition {
|
||||
.item-wrapper {
|
||||
color: #15bc83;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.item-wrapper {
|
||||
background: #3296fa;
|
||||
box-shadow: 0 10px 20px 0 rgba(50, 150, 250, 0.4);
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
&:active {
|
||||
.item-wrapper {
|
||||
box-shadow: none;
|
||||
background: #eaeaea;
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,297 +0,0 @@
|
||||
<!-- eslint-disable vue/no-mutating-props -->
|
||||
<!--
|
||||
* @Date: 2022-09-21 14:41:53
|
||||
* @LastEditors: StavinLi 495727881@qq.com
|
||||
* @LastEditTime: 2023-05-24 15:20:24
|
||||
* @FilePath: /Workflow-Vue3/src/components/nodeWrap.vue
|
||||
-->
|
||||
<template>
|
||||
<div class="node-wrap" v-if="nodeConfig.type < 3">
|
||||
<div class="node-wrap-box" :class="(nodeConfig.type == 0 ? 'start-node ' : '') +(isTried && nodeConfig.error ? 'active error' : '')">
|
||||
<div class="title" :style="`background: rgb(${bgColors[nodeConfig.type]});`">
|
||||
<span v-if="nodeConfig.type == 0">{{ nodeConfig.nodeName }}</span>
|
||||
<template v-else>
|
||||
<span class="iconfont">{{nodeConfig.type == 1?'':''}}</span>
|
||||
<input
|
||||
v-if="isInput"
|
||||
type="text"
|
||||
class="ant-input editable-title-input"
|
||||
@blur="blurEvent()"
|
||||
@focus="$event.currentTarget.select()"
|
||||
v-focus
|
||||
v-model="nodeConfig.nodeName"
|
||||
:placeholder="defaultText"
|
||||
/>
|
||||
<span v-else class="editable-title" @click="clickEvent()">{{ nodeConfig.nodeName }}</span>
|
||||
<i class="anticon anticon-close close" @click="delNode"></i>
|
||||
</template>
|
||||
</div>
|
||||
<div class="content" @click="setPerson">
|
||||
<div class="text">
|
||||
<span class="placeholder" v-if="!showText">请选择{{defaultText}}</span>
|
||||
{{showText}}
|
||||
</div>
|
||||
<i class="anticon anticon-right arrow"></i>
|
||||
</div>
|
||||
<div class="error_tip" v-if="isTried && nodeConfig.error">
|
||||
<i class="anticon anticon-exclamation-circle"></i>
|
||||
</div>
|
||||
</div>
|
||||
<addNode v-model:childNodeP="nodeConfig.childNode" />
|
||||
</div>
|
||||
<div class="branch-wrap" v-if="nodeConfig.type == 4">
|
||||
<div class="branch-box-wrap">
|
||||
<div class="branch-box">
|
||||
<button class="add-branch" @click="addTerm">添加条件</button>
|
||||
<div class="col-box" v-for="(item, index) in nodeConfig.conditionNodes" :key="index">
|
||||
<div class="condition-node">
|
||||
<div class="condition-node-box">
|
||||
<div class="auto-judge" :class="isTried && item.error ? 'error active' : ''">
|
||||
<div class="sort-left" v-if="index != 0" @click="arrTransfer(index, -1)"><</div>
|
||||
<div class="title-wrapper">
|
||||
<input
|
||||
v-if="isInputList[index]"
|
||||
type="text"
|
||||
class="ant-input editable-title-input"
|
||||
@blur="blurEvent(index)"
|
||||
@focus="$event.currentTarget.select()"
|
||||
v-model="item.nodeName"
|
||||
/>
|
||||
<span v-else class="editable-title" @click="clickEvent(index)">{{ item.nodeName }}</span>
|
||||
<span class="priority-title" @click="setPerson(item.priorityLevel)">优先级{{ item.priorityLevel }}</span>
|
||||
<i class="anticon anticon-close close" @click="delTerm(index)"></i>
|
||||
</div>
|
||||
<div class="sort-right" v-if="index != nodeConfig.conditionNodes.length - 1" @click="arrTransfer(index)">></div>
|
||||
<div class="content" @click="setPerson(item.priorityLevel)">{{ conditionStr(nodeConfig, index) }}</div>
|
||||
<div class="error_tip" v-if="isTried && item.error">
|
||||
<i class="anticon anticon-exclamation-circle"></i>
|
||||
</div>
|
||||
</div>
|
||||
<addNode v-model:childNodeP="item.childNode" />
|
||||
</div>
|
||||
</div>
|
||||
<nodeWrap v-if="item.childNode" v-model:nodeConfig="item.childNode" />
|
||||
<template v-if="index == 0">
|
||||
<div class="top-left-cover-line"></div>
|
||||
<div class="bottom-left-cover-line"></div>
|
||||
</template>
|
||||
<template v-if="index == nodeConfig.conditionNodes.length - 1">
|
||||
<div class="top-right-cover-line"></div>
|
||||
<div class="bottom-right-cover-line"></div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<addNode v-model:childNodeP="nodeConfig.childNode" />
|
||||
</div>
|
||||
</div>
|
||||
<nodeWrap v-if="nodeConfig.childNode" v-model:nodeConfig="nodeConfig.childNode" />
|
||||
</template>
|
||||
<script setup>
|
||||
import addNode from './addNode.vue'
|
||||
import { onMounted, ref, watch, getCurrentInstance, computed } from 'vue'
|
||||
import {
|
||||
arrToStr,
|
||||
conditionStr,
|
||||
setApproverStr,
|
||||
copyerStr,
|
||||
bgColors,
|
||||
placeholderList
|
||||
} from './util'
|
||||
import { useWorkFlowStoreWithOut } from '@/store/modules/simpleWorkflow'
|
||||
let _uid = getCurrentInstance().uid
|
||||
|
||||
let props = defineProps({
|
||||
nodeConfig: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
flowPermission: {
|
||||
type: Object,
|
||||
// eslint-disable-next-line vue/require-valid-default-prop
|
||||
default: () => []
|
||||
}
|
||||
})
|
||||
|
||||
let defaultText = computed(() => {
|
||||
return placeholderList[props.nodeConfig.type]
|
||||
})
|
||||
let showText = computed(() => {
|
||||
if (props.nodeConfig.type == 0) return arrToStr(props.flowPermission) || '所有人'
|
||||
if (props.nodeConfig.type == 1) return setApproverStr(props.nodeConfig)
|
||||
return copyerStr(props.nodeConfig)
|
||||
})
|
||||
|
||||
let isInputList = ref([])
|
||||
let isInput = ref(false)
|
||||
const resetConditionNodesErr = () => {
|
||||
for (var i = 0; i < props.nodeConfig.conditionNodes.length; i++) {
|
||||
// eslint-disable-next-line vue/no-mutating-props
|
||||
props.nodeConfig.conditionNodes[i].error =
|
||||
conditionStr(props.nodeConfig, i) == '请设置条件' &&
|
||||
i != props.nodeConfig.conditionNodes.length - 1
|
||||
}
|
||||
}
|
||||
onMounted(() => {
|
||||
if (props.nodeConfig.type == 1) {
|
||||
// eslint-disable-next-line vue/no-mutating-props
|
||||
props.nodeConfig.error = !setApproverStr(props.nodeConfig)
|
||||
} else if (props.nodeConfig.type == 2) {
|
||||
// eslint-disable-next-line vue/no-mutating-props
|
||||
props.nodeConfig.error = !copyerStr(props.nodeConfig)
|
||||
} else if (props.nodeConfig.type == 4) {
|
||||
resetConditionNodesErr()
|
||||
}
|
||||
})
|
||||
let emits = defineEmits(['update:flowPermission', 'update:nodeConfig'])
|
||||
let store = useWorkFlowStoreWithOut()
|
||||
let {
|
||||
setPromoter,
|
||||
setApprover,
|
||||
setCopyer,
|
||||
setCondition,
|
||||
setFlowPermission,
|
||||
setApproverConfig,
|
||||
setCopyerConfig,
|
||||
setConditionsConfig
|
||||
} = store
|
||||
let isTried = computed(() => store.isTried)
|
||||
let flowPermission1 = computed(() => store.flowPermission1)
|
||||
let approverConfig1 = computed(() => store.approverConfig1)
|
||||
let copyerConfig1 = computed(() => store.copyerConfig1)
|
||||
let conditionsConfig1 = computed(() => store.conditionsConfig1)
|
||||
watch(flowPermission1, (flow) => {
|
||||
if (flow.flag && flow.id === _uid) {
|
||||
emits('update:flowPermission', flow.value)
|
||||
}
|
||||
})
|
||||
watch(approverConfig1, (approver) => {
|
||||
if (approver.flag && approver.id === _uid) {
|
||||
emits('update:nodeConfig', approver.value)
|
||||
}
|
||||
})
|
||||
watch(copyerConfig1, (copyer) => {
|
||||
if (copyer.flag && copyer.id === _uid) {
|
||||
emits('update:nodeConfig', copyer.value)
|
||||
}
|
||||
})
|
||||
watch(conditionsConfig1, (condition) => {
|
||||
if (condition.flag && condition.id === _uid) {
|
||||
emits('update:nodeConfig', condition.value)
|
||||
}
|
||||
})
|
||||
|
||||
const clickEvent = (index) => {
|
||||
if (index || index === 0) {
|
||||
isInputList.value[index] = true
|
||||
} else {
|
||||
isInput.value = true
|
||||
}
|
||||
}
|
||||
const blurEvent = (index) => {
|
||||
if (index || index === 0) {
|
||||
isInputList.value[index] = false
|
||||
// eslint-disable-next-line vue/no-mutating-props
|
||||
props.nodeConfig.conditionNodes[index].nodeName =
|
||||
props.nodeConfig.conditionNodes[index].nodeName || '条件'
|
||||
} else {
|
||||
isInput.value = false
|
||||
// eslint-disable-next-line vue/no-mutating-props
|
||||
props.nodeConfig.nodeName = props.nodeConfig.nodeName || defaultText
|
||||
}
|
||||
}
|
||||
const delNode = () => {
|
||||
emits('update:nodeConfig', props.nodeConfig.childNode)
|
||||
}
|
||||
const addTerm = () => {
|
||||
let len = props.nodeConfig.conditionNodes.length + 1
|
||||
// eslint-disable-next-line vue/no-mutating-props
|
||||
props.nodeConfig.conditionNodes.push({
|
||||
nodeName: '条件' + len,
|
||||
type: 3,
|
||||
priorityLevel: len,
|
||||
conditionList: [],
|
||||
nodeUserList: [],
|
||||
childNode: null
|
||||
})
|
||||
resetConditionNodesErr()
|
||||
emits('update:nodeConfig', props.nodeConfig)
|
||||
}
|
||||
const delTerm = (index) => {
|
||||
// eslint-disable-next-line vue/no-mutating-props
|
||||
props.nodeConfig.conditionNodes.splice(index, 1)
|
||||
props.nodeConfig.conditionNodes.map((item, index) => {
|
||||
item.priorityLevel = index + 1
|
||||
item.nodeName = `条件${index + 1}`
|
||||
})
|
||||
resetConditionNodesErr()
|
||||
emits('update:nodeConfig', props.nodeConfig)
|
||||
if (props.nodeConfig.conditionNodes.length == 1) {
|
||||
if (props.nodeConfig.childNode) {
|
||||
if (props.nodeConfig.conditionNodes[0].childNode) {
|
||||
reData(props.nodeConfig.conditionNodes[0].childNode, props.nodeConfig.childNode)
|
||||
} else {
|
||||
// eslint-disable-next-line vue/no-mutating-props
|
||||
props.nodeConfig.conditionNodes[0].childNode = props.nodeConfig.childNode
|
||||
}
|
||||
}
|
||||
emits('update:nodeConfig', props.nodeConfig.conditionNodes[0].childNode)
|
||||
}
|
||||
}
|
||||
const reData = (data, addData) => {
|
||||
if (!data.childNode) {
|
||||
data.childNode = addData
|
||||
} else {
|
||||
reData(data.childNode, addData)
|
||||
}
|
||||
}
|
||||
const setPerson = (priorityLevel) => {
|
||||
var { type } = props.nodeConfig
|
||||
if (type == 0) {
|
||||
setPromoter(true)
|
||||
setFlowPermission({
|
||||
value: props.flowPermission,
|
||||
flag: false,
|
||||
id: _uid
|
||||
})
|
||||
} else if (type == 1) {
|
||||
setApprover(true)
|
||||
setApproverConfig({
|
||||
value: {
|
||||
...JSON.parse(JSON.stringify(props.nodeConfig)),
|
||||
...{ settype: props.nodeConfig.settype ? props.nodeConfig.settype : 1 }
|
||||
},
|
||||
flag: false,
|
||||
id: _uid
|
||||
})
|
||||
} else if (type == 2) {
|
||||
setCopyer(true)
|
||||
setCopyerConfig({
|
||||
value: JSON.parse(JSON.stringify(props.nodeConfig)),
|
||||
flag: false,
|
||||
id: _uid
|
||||
})
|
||||
} else {
|
||||
setCondition(true)
|
||||
setConditionsConfig({
|
||||
value: JSON.parse(JSON.stringify(props.nodeConfig)),
|
||||
priorityLevel,
|
||||
flag: false,
|
||||
id: _uid
|
||||
})
|
||||
}
|
||||
}
|
||||
const arrTransfer = (index, type = 1) => {
|
||||
//向左-1,向右1
|
||||
// eslint-disable-next-line vue/no-mutating-props
|
||||
props.nodeConfig.conditionNodes[index] = props.nodeConfig.conditionNodes.splice(
|
||||
index + type,
|
||||
1,
|
||||
props.nodeConfig.conditionNodes[index]
|
||||
)[0]
|
||||
props.nodeConfig.conditionNodes.map((item, index) => {
|
||||
item.priorityLevel = index + 1
|
||||
})
|
||||
resetConditionNodesErr()
|
||||
emits('update:nodeConfig', props.nodeConfig)
|
||||
}
|
||||
</script>
|
||||
@ -1,165 +0,0 @@
|
||||
/**
|
||||
* todo
|
||||
*/
|
||||
export const arrToStr = (arr?: [{ name: string }]) => {
|
||||
if (arr) {
|
||||
return arr
|
||||
.map((item) => {
|
||||
return item.name
|
||||
})
|
||||
.toString()
|
||||
}
|
||||
}
|
||||
|
||||
export const setApproverStr = (nodeConfig: any) => {
|
||||
if (nodeConfig.settype == 1) {
|
||||
if (nodeConfig.nodeUserList.length == 1) {
|
||||
return nodeConfig.nodeUserList[0].name
|
||||
} else if (nodeConfig.nodeUserList.length > 1) {
|
||||
if (nodeConfig.examineMode == 1) {
|
||||
return arrToStr(nodeConfig.nodeUserList)
|
||||
} else if (nodeConfig.examineMode == 2) {
|
||||
return nodeConfig.nodeUserList.length + '人会签'
|
||||
}
|
||||
}
|
||||
} else if (nodeConfig.settype == 2) {
|
||||
const level =
|
||||
nodeConfig.directorLevel == 1 ? '直接主管' : '第' + nodeConfig.directorLevel + '级主管'
|
||||
if (nodeConfig.examineMode == 1) {
|
||||
return level
|
||||
} else if (nodeConfig.examineMode == 2) {
|
||||
return level + '会签'
|
||||
}
|
||||
} else if (nodeConfig.settype == 4) {
|
||||
if (nodeConfig.selectRange == 1) {
|
||||
return '发起人自选'
|
||||
} else {
|
||||
if (nodeConfig.nodeUserList.length > 0) {
|
||||
if (nodeConfig.selectRange == 2) {
|
||||
return '发起人自选'
|
||||
} else {
|
||||
return '发起人从' + nodeConfig.nodeUserList[0].name + '中自选'
|
||||
}
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
} else if (nodeConfig.settype == 5) {
|
||||
return '发起人自己'
|
||||
} else if (nodeConfig.settype == 7) {
|
||||
return '从直接主管到通讯录中级别最高的第' + nodeConfig.examineEndDirectorLevel + '个层级主管'
|
||||
}
|
||||
}
|
||||
|
||||
export const copyerStr = (nodeConfig: any) => {
|
||||
if (nodeConfig.nodeUserList.length != 0) {
|
||||
return arrToStr(nodeConfig.nodeUserList)
|
||||
} else {
|
||||
if (nodeConfig.ccSelfSelectFlag == 1) {
|
||||
return '发起人自选'
|
||||
}
|
||||
}
|
||||
}
|
||||
export const conditionStr = (nodeConfig, index) => {
|
||||
const { conditionList, nodeUserList } = nodeConfig.conditionNodes[index]
|
||||
if (conditionList.length == 0) {
|
||||
return index == nodeConfig.conditionNodes.length - 1 &&
|
||||
nodeConfig.conditionNodes[0].conditionList.length != 0
|
||||
? '其他条件进入此流程'
|
||||
: '请设置条件'
|
||||
} else {
|
||||
let str = ''
|
||||
for (let i = 0; i < conditionList.length; i++) {
|
||||
const {
|
||||
columnId,
|
||||
columnType,
|
||||
showType,
|
||||
showName,
|
||||
optType,
|
||||
zdy1,
|
||||
opt1,
|
||||
zdy2,
|
||||
opt2,
|
||||
fixedDownBoxValue
|
||||
} = conditionList[i]
|
||||
if (columnId == 0) {
|
||||
if (nodeUserList.length != 0) {
|
||||
str += '发起人属于:'
|
||||
str +=
|
||||
nodeUserList
|
||||
.map((item) => {
|
||||
return item.name
|
||||
})
|
||||
.join('或') + ' 并且 '
|
||||
}
|
||||
}
|
||||
if (columnType == 'String' && showType == '3') {
|
||||
if (zdy1) {
|
||||
str += showName + '属于:' + dealStr(zdy1, JSON.parse(fixedDownBoxValue)) + ' 并且 '
|
||||
}
|
||||
}
|
||||
if (columnType == 'Double') {
|
||||
if (optType != 6 && zdy1) {
|
||||
const optTypeStr = ['', '<', '>', '≤', '=', '≥'][optType]
|
||||
str += `${showName} ${optTypeStr} ${zdy1} 并且 `
|
||||
} else if (optType == 6 && zdy1 && zdy2) {
|
||||
str += `${zdy1} ${opt1} ${showName} ${opt2} ${zdy2} 并且 `
|
||||
}
|
||||
}
|
||||
}
|
||||
return str ? str.substring(0, str.length - 4) : '请设置条件'
|
||||
}
|
||||
}
|
||||
|
||||
export const dealStr = (str: string, obj) => {
|
||||
const arr = []
|
||||
const list = str.split(',')
|
||||
for (const elem in obj) {
|
||||
list.map((item) => {
|
||||
if (item == elem) {
|
||||
arr.push(obj[elem].value)
|
||||
}
|
||||
})
|
||||
}
|
||||
return arr.join('或')
|
||||
}
|
||||
|
||||
export const removeEle = (arr, elem, key = 'id') => {
|
||||
let includesIndex
|
||||
arr.map((item, index) => {
|
||||
if (item[key] == elem[key]) {
|
||||
includesIndex = index
|
||||
}
|
||||
})
|
||||
arr.splice(includesIndex, 1)
|
||||
}
|
||||
|
||||
export const bgColors = ['87, 106, 149', '255, 148, 62', '50, 150, 250']
|
||||
export const placeholderList = ['发起人', '审核人', '抄送人']
|
||||
export const setTypes = [
|
||||
{ value: 1, label: '指定成员' },
|
||||
{ value: 2, label: '主管' },
|
||||
{ value: 4, label: '发起人自选' },
|
||||
{ value: 5, label: '发起人自己' },
|
||||
{ value: 7, label: '连续多级主管' }
|
||||
]
|
||||
|
||||
export const selectModes = [
|
||||
{ value: 1, label: '选一个人' },
|
||||
{ value: 2, label: '选多个人' }
|
||||
]
|
||||
|
||||
export const selectRanges = [
|
||||
{ value: 1, label: '全公司' },
|
||||
{ value: 2, label: '指定成员' },
|
||||
{ value: 3, label: '指定角色' }
|
||||
]
|
||||
|
||||
export const optTypes = [
|
||||
{ value: '1', label: '小于' },
|
||||
{ value: '2', label: '大于' },
|
||||
{ value: '3', label: '小于等于' },
|
||||
{ value: '4', label: '等于' },
|
||||
{ value: '5', label: '大于等于' },
|
||||
{ value: '6', label: '介于两个数之间' }
|
||||
]
|
||||
@ -0,0 +1,118 @@
|
||||
<template>
|
||||
<!-- 发起人节点 -->
|
||||
<StartUserNode
|
||||
v-if="currentNode && currentNode.type === NodeType.START_USER_NODE"
|
||||
:flow-node="currentNode"
|
||||
/>
|
||||
<!-- 审批节点 -->
|
||||
<UserTaskNode
|
||||
v-if="currentNode && currentNode.type === NodeType.USER_TASK_NODE"
|
||||
:flow-node="currentNode"
|
||||
@update:flow-node="handleModelValueUpdate"
|
||||
@find:parent-node="findFromParentNode"
|
||||
/>
|
||||
<!-- 抄送节点 -->
|
||||
<CopyTaskNode
|
||||
v-if="currentNode && currentNode.type === NodeType.COPY_TASK_NODE"
|
||||
:flow-node="currentNode"
|
||||
@update:flow-node="handleModelValueUpdate"
|
||||
/>
|
||||
<!-- 条件节点 -->
|
||||
<ExclusiveNode
|
||||
v-if="currentNode && currentNode.type === NodeType.CONDITION_BRANCH_NODE"
|
||||
:flow-node="currentNode"
|
||||
@update:model-value="handleModelValueUpdate"
|
||||
@find:parent-node="findFromParentNode"
|
||||
/>
|
||||
<!-- 并行节点 -->
|
||||
<ParallelNode
|
||||
v-if="currentNode && currentNode.type === NodeType.PARALLEL_BRANCH_NODE"
|
||||
:flow-node="currentNode"
|
||||
@update:model-value="handleModelValueUpdate"
|
||||
@find:parent-node="findFromParentNode"
|
||||
/>
|
||||
<!-- 包容分支节点 -->
|
||||
<InclusiveNode
|
||||
v-if="currentNode && currentNode.type === NodeType.INCLUSIVE_BRANCH_NODE"
|
||||
:flow-node="currentNode"
|
||||
@update:model-value="handleModelValueUpdate"
|
||||
@find:parent-node="findFromParentNode"
|
||||
/>
|
||||
<!-- 递归显示孩子节点 -->
|
||||
<ProcessNodeTree
|
||||
v-if="currentNode && currentNode.childNode"
|
||||
v-model:flow-node="currentNode.childNode"
|
||||
:parent-node="currentNode"
|
||||
@find:recursive-find-parent-node="recursiveFindParentNode"
|
||||
/>
|
||||
|
||||
<!-- 结束节点 -->
|
||||
<EndEventNode
|
||||
v-if="currentNode && currentNode.type === NodeType.END_EVENT_NODE"
|
||||
:flow-node="currentNode"
|
||||
/>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import StartUserNode from './nodes/StartUserNode.vue'
|
||||
import EndEventNode from './nodes/EndEventNode.vue'
|
||||
import UserTaskNode from './nodes/UserTaskNode.vue'
|
||||
import CopyTaskNode from './nodes/CopyTaskNode.vue'
|
||||
import ExclusiveNode from './nodes/ExclusiveNode.vue'
|
||||
import ParallelNode from './nodes/ParallelNode.vue'
|
||||
import InclusiveNode from './nodes/InclusiveNode.vue'
|
||||
import { SimpleFlowNode, NodeType } from './consts'
|
||||
import { useWatchNode } from './node'
|
||||
defineOptions({
|
||||
name: 'ProcessNodeTree'
|
||||
})
|
||||
const props = defineProps({
|
||||
parentNode: {
|
||||
type: Object as () => SimpleFlowNode,
|
||||
default: () => null
|
||||
},
|
||||
flowNode: {
|
||||
type: Object as () => SimpleFlowNode,
|
||||
default: () => null
|
||||
}
|
||||
})
|
||||
const emits = defineEmits<{
|
||||
'update:flowNode': [node: SimpleFlowNode | undefined]
|
||||
'find:recursiveFindParentNode': [
|
||||
nodeList: SimpleFlowNode[],
|
||||
curentNode: SimpleFlowNode,
|
||||
nodeType: number
|
||||
]
|
||||
}>()
|
||||
|
||||
const currentNode = useWatchNode(props)
|
||||
|
||||
// 用于删除节点
|
||||
const handleModelValueUpdate = (updateValue) => {
|
||||
emits('update:flowNode', updateValue)
|
||||
}
|
||||
|
||||
const findFromParentNode = (nodeList: SimpleFlowNode[], nodeType: number) => {
|
||||
emits('find:recursiveFindParentNode', nodeList, props.parentNode, nodeType)
|
||||
}
|
||||
|
||||
// 递归从父节点中查询匹配的节点
|
||||
const recursiveFindParentNode = (
|
||||
nodeList: SimpleFlowNode[],
|
||||
findNode: SimpleFlowNode,
|
||||
nodeType: number
|
||||
) => {
|
||||
if (!findNode) {
|
||||
return
|
||||
}
|
||||
if (findNode.type === NodeType.START_USER_NODE) {
|
||||
nodeList.push(findNode)
|
||||
return
|
||||
}
|
||||
|
||||
if (findNode.type === nodeType) {
|
||||
nodeList.push(findNode)
|
||||
}
|
||||
emits('find:recursiveFindParentNode', nodeList, props.parentNode, nodeType)
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
@ -0,0 +1,48 @@
|
||||
<template>
|
||||
<SimpleProcessModel :flow-node="simpleModel" :readonly="true" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useWatchNode } from './node'
|
||||
import { SimpleFlowNode } from './consts'
|
||||
|
||||
defineOptions({
|
||||
name: 'SimpleProcessViewer'
|
||||
})
|
||||
|
||||
const props = defineProps({
|
||||
flowNode: {
|
||||
type: Object as () => SimpleFlowNode,
|
||||
required: true
|
||||
},
|
||||
// 流程任务
|
||||
tasks: {
|
||||
type: Array,
|
||||
default: () => [] as any[]
|
||||
},
|
||||
// 流程实例
|
||||
processInstance: {
|
||||
type: Object,
|
||||
default: () => undefined
|
||||
}
|
||||
})
|
||||
const approveTasks = ref<any[]>(props.tasks)
|
||||
const currentProcessInstance = ref(props.processInstance)
|
||||
const simpleModel = useWatchNode(props)
|
||||
watch(
|
||||
() => props.tasks,
|
||||
(newValue) => {
|
||||
approveTasks.value = newValue
|
||||
}
|
||||
)
|
||||
watch(
|
||||
() => props.processInstance,
|
||||
(newValue) => {
|
||||
currentProcessInstance.value = newValue
|
||||
}
|
||||
)
|
||||
|
||||
provide('tasks', approveTasks)
|
||||
provide('processInstance', currentProcessInstance)
|
||||
</script>
|
||||
p
|
||||
@ -0,0 +1,5 @@
|
||||
import SimpleProcessDesigner from './SimpleProcessDesigner.vue'
|
||||
import SimpleProcessViewer from './SimpleProcessViewer.vue'
|
||||
import '../theme/simple-process-designer.scss'
|
||||
|
||||
export { SimpleProcessDesigner, SimpleProcessViewer}
|
||||
@ -0,0 +1,41 @@
|
||||
import { TimeUnitType, ApproveType, APPROVE_TYPE } from './consts'
|
||||
|
||||
// 获取条件节点默认的名称
|
||||
export const getDefaultConditionNodeName = (index: number, defaultFlow: boolean | undefined): string => {
|
||||
if (defaultFlow) {
|
||||
return '其它情况'
|
||||
}
|
||||
return '条件' + (index + 1)
|
||||
}
|
||||
|
||||
// 获取包容分支条件节点默认的名称
|
||||
export const getDefaultInclusiveConditionNodeName = (index: number, defaultFlow: boolean | undefined): string => {
|
||||
if (defaultFlow) {
|
||||
return '其它情况'
|
||||
}
|
||||
return '包容条件' + (index + 1)
|
||||
}
|
||||
|
||||
export const convertTimeUnit = (strTimeUnit: string) => {
|
||||
if (strTimeUnit === 'M') {
|
||||
return TimeUnitType.MINUTE
|
||||
}
|
||||
if (strTimeUnit === 'H') {
|
||||
return TimeUnitType.HOUR
|
||||
}
|
||||
if (strTimeUnit === 'D') {
|
||||
return TimeUnitType.DAY
|
||||
}
|
||||
return TimeUnitType.HOUR
|
||||
}
|
||||
|
||||
export const getApproveTypeText = (approveType: ApproveType): string => {
|
||||
let approveTypeText = ''
|
||||
APPROVE_TYPE.forEach((item) => {
|
||||
if (item.value === approveType) {
|
||||
approveTypeText = item.label
|
||||
return
|
||||
}
|
||||
})
|
||||
return approveTypeText
|
||||
}
|
||||