feat(milestone): [milestone] Adapt milestone component smb theme (#1996)

This commit is contained in:
MomoPoppy 2024-08-28 02:25:41 -07:00 committed by GitHub
parent a3365063a0
commit cd6cf7fb68
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 296 additions and 66 deletions

View File

@ -1,6 +1,18 @@
<template>
<div class="demo-milestone">
<div>场景1 默认</div>
<br />
<tiny-milestone :data="milestoneData"></tiny-milestone>
<br />
<br />
<div>场景2 自定义状态色</div>
<br />
<tiny-milestone :data="milestoneData" :milestones-status="statusMap"></tiny-milestone>
<br />
<br />
<div>场景3 自定义状态色 + 实心显示</div>
<br />
<tiny-milestone :data="milestoneData" :milestones-status="statusMap" solid></tiny-milestone>
</div>
</template>
@ -13,14 +25,15 @@ const statusMap = ref({
// status = completed
completed: 'var(--ti-common-color-line-active)',
// status = doing
doing: '#7ED321',
doing: '#9ec591',
// status = back
back: '#f5222d',
back: '#97a7db',
// status = end
end: '#faad14',
// status = cancel
cancel: '#d9d9d9'
})
//
const milestoneData = ref([
{
@ -70,16 +83,10 @@ const milestoneData = ref([
status: 'end',
flags: [
{
status: 'completed',
status: 'cancel',
content: 'test6'
}
]
}
])
</script>
<style scoped>
.demo-milestone ::v-deep .tiny-milestone__description-status {
margin-top: 4px;
}
</style>

View File

@ -4,14 +4,14 @@ test('基本用法', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).not.toBeNull())
await page.goto('milestone#basic-usage')
const milestone = page.locator('.tiny-milestone')
const nodes = page.locator('.tiny-milestone__node')
const nodeIcons = page.locator('.tiny-milestone__icon')
const nodeLines = page.locator('.tiny-milestone__line')
const nodeTitles = page.locator('.tiny-milestone__description-name')
const nodeDates = page.locator('.tiny-milestone__description-status')
const flags = page.locator('.tiny-milestone__flag-content')
const flagLines = page.locator('.tiny-milestone__flag-line')
const milestone = page.locator('.tiny-milestone').nth(1)
const nodes = milestone.locator('.tiny-milestone__node')
const nodeIcons = milestone.locator('.tiny-milestone__icon')
const nodeLines = milestone.locator('.tiny-milestone__line')
const nodeTitles = milestone.locator('.tiny-milestone__description-name')
const nodeDates = milestone.locator('.tiny-milestone__description-status')
const flags = milestone.locator('.tiny-milestone__flag-content')
const flagLines = milestone.locator('.tiny-milestone__flag-line')
const flagLineDots = flagLines.locator('.tiny-milestone__dot')
const nodeCount = 6
const iconClasss = [
@ -34,9 +34,9 @@ test('基本用法', async ({ page }) => {
'box-shadow': 'rgba(94, 124, 224, 0.4) 0px 0px 0px 4px'
},
{
'background-color': 'rgb(126, 211, 33)',
'background-color': 'rgb(158, 197, 145)',
'color': 'rgb(255, 255, 255)',
'box-shadow': 'rgba(126, 211, 33, 0.4) 0px 0px 0px 4px'
'box-shadow': 'rgba(158, 197, 145, 0.4) 0px 0px 0px 4px'
},
{
'background-color': 'rgb(217, 217, 217)',
@ -44,9 +44,9 @@ test('基本用法', async ({ page }) => {
'box-shadow': 'rgba(217, 217, 217, 0.4) 0px 0px 0px 4px'
},
{
'background-color': 'rgb(245, 34, 45)',
'background-color': 'rgb(151, 167, 219)',
'color': 'rgb(255, 255, 255)',
'box-shadow': 'rgba(245, 34, 45, 0.4) 0px 0px 0px 4px'
'box-shadow': 'rgba(151, 167, 219, 0.4) 0px 0px 0px 4px'
},
{
'background-color': 'rgb(250, 173, 20)',
@ -56,7 +56,7 @@ test('基本用法', async ({ page }) => {
]
const titles = ['completed 状态', 'completed 状态', 'doing 状态', 'cancel 状态', 'back 状态', 'end 状态']
const flagContents = [/引导用户按照流程完成任务/, /test7欢迎使用vui/, /test8/, /test6/]
const flagLineColors = ['rgb(245, 34, 45)', 'rgb(245, 34, 45)', 'rgb(126, 211, 33)', 'rgb(94, 124, 224)']
const flagLineColors = ['rgb(151, 167, 219)', 'rgb(151, 167, 219)', 'rgb(158, 197, 145)', 'rgb(217, 217, 217)']
await expect(nodes).toHaveCount(nodeCount)
await expect(nodeLines).toHaveCount(nodeCount)
@ -89,7 +89,7 @@ test('基本用法', async ({ page }) => {
}
if (i < 4) {
await expect(flags.nth(i)).toHaveCSS('width', '58px')
await expect(flags.nth(i)).toHaveCSS('padding', '0px')
await expect(flags.nth(i)).toHaveCSS('padding', '0px 4px')
await expect(flags.nth(i)).toHaveText(flagContents[i])
await expect(flagLines.nth(i)).toHaveCSS('width', '1px')
await expect(flagLines.nth(i)).toHaveCSS('height', '30px')

View File

@ -1,6 +1,18 @@
<template>
<div class="demo-milestone">
<div>场景1 默认</div>
<br />
<tiny-milestone :data="milestoneData"></tiny-milestone>
<br />
<br />
<div>场景2 自定义状态色</div>
<br />
<tiny-milestone :data="milestoneData" :milestones-status="statusMap"></tiny-milestone>
<br />
<br />
<div>场景3 自定义状态色 + 实心显示</div>
<br />
<tiny-milestone :data="milestoneData" :milestones-status="statusMap" solid></tiny-milestone>
</div>
</template>
@ -16,11 +28,11 @@ export default {
// statusMap milestoneDatastatus
statusMap: {
// status = completed
completed: 'var(--ti-common-color-line-active)',
completed: '#1890ff',
// status = doing
doing: '#7ED321',
doing: '#9ec591',
// status = back
back: '#f5222d',
back: '#97a7db',
// status = end
end: '#faad14',
// status = cancel
@ -75,7 +87,7 @@ export default {
status: 'end',
flags: [
{
status: 'completed',
status: 'cancel',
content: 'test6'
}
]
@ -85,9 +97,3 @@ export default {
}
}
</script>
<style scoped>
.demo-milestone ::v-deep .tiny-milestone__description-status {
margin-top: 4px;
}
</style>

View File

@ -14,6 +14,7 @@ import TimeSpinner from './src/time-spinner'
import Time from './src/time-spinner'
import UploadList from './src/upload-list'
import BreadcrumbItem from './src/breadcrumb-item'
import Milestone from './src/milestone'
import TransferPanel from './src/transfer-panel'
import { version } from './package.json'
@ -37,6 +38,7 @@ export default {
Time,
BreadcrumbItem,
UploadList,
Milestone,
TransferPanel
}
}

View File

@ -0,0 +1,68 @@
export default {
renderless: (props, hooks, { emit, constants }, api) => {
const state = api.state
const smbConstants = {
STATUS_COLOR_MAP: {
DEFAULT: {
BORDER_COLOR: '#C2C2C2',
BACKGROUND_COLOR: '#FFFFFF',
COLOR: '#191919',
BOX_SHADOW_PX: '0px 0px 0px 4px',
FLAG_CONTENT_CLS: '.content'
},
COMPLETED: {
BORDER_COLOR: '#191919',
BACKGROUND_COLOR: '#FFFFFF',
COLOR: '#191919',
BOX_SHADOW_PX: '0px 0px 0px 4px',
FLAG_CONTENT_CLS: '.content'
},
DOING: {
BORDER_COLOR: '#191919',
BACKGROUND_COLOR: '#191919',
COLOR: '#FFFFFF',
BOX_SHADOW_PX: '0px 0px 0px 4px',
FLAG_CONTENT_CLS: '.content'
}
}
}
return {
getMileIcon: (node) => {
const status = node[props.statusField]
// 状态色
const statusColor = props.milestonesStatus[status]
if (props.solid || status === constants.STATUS_MAP.DOING) {
return {
'background-color': statusColor || smbConstants.STATUS_COLOR_MAP.DOING.BACKGROUND_COLOR + '!important',
color: smbConstants.STATUS_COLOR_MAP.DOING.COLOR + '!important',
'border-color': statusColor || smbConstants.STATUS_COLOR_MAP.DOING.BORDER_COLOR,
boxShadow: 'unset'
}
}
if (status === constants.STATUS_MAP.COMPLETED) {
return {
'background-color': smbConstants.STATUS_COLOR_MAP.COMPLETED.BACKGROUND_COLOR + '!important',
color: statusColor || smbConstants.STATUS_COLOR_MAP.COMPLETED.COLOR + '!important',
'border-color': statusColor || smbConstants.STATUS_COLOR_MAP.COMPLETED.BORDER_COLOR,
boxShadow: 'unset'
}
}
return {
background: smbConstants.STATUS_COLOR_MAP.DEFAULT.BACKGROUND_COLOR + '!important',
color: statusColor || smbConstants.STATUS_COLOR_MAP.DEFAULT.COLOR + '!important',
'border-color': statusColor || smbConstants.STATUS_COLOR_MAP.DEFAULT.BORDER_COLOR,
boxShadow: 'unset'
}
},
getFlagStyle: ({ index, idx }) => {
return {
left: `calc(${(100 / props.data[props.flagBefore ? index : index + 1][props.flagField].length) * idx}% + ${idx * 8}px)`
}
}
}
}
}

View File

@ -20,7 +20,7 @@ import type {
IMilestoneFlagOperateParams
} from '@/types'
const hexToRgb = (hex: string): { r: number; g: number; b: number } => {
export const hexToRgb = (hex: string): { r: number; g: number; b: number } => {
if (hex.includes('var')) {
hex = hex.replace(/var\(|\)/g, '')
hex = getComputedStyle(document.documentElement).getPropertyValue(hex)
@ -115,3 +115,11 @@ export const handleFlagClick =
emit('flagclick', idx, flag) // deprecated 原事件flagclick v3.5.0废弃v3.17.0移除;移除原因:命名规范
emit('flag-click', idx, flag)
}
export const getFlagStyle =
(props) =>
({ index, idx }) => {
return {
left: `calc(${(100 / (props.data[props.flagBefore ? index : index + 1][props.flagField].length + 1)) * (idx + 1)}% - 29px)`
}
}

View File

@ -16,7 +16,16 @@ import type {
ISharedRenderlessParamHooks,
IMilestoneRenderlessParamUtils
} from '@/types'
import { handleClick, flagOperate, getMileIcon, getMileContent, getLineColor, handleFlagClick } from './index'
import {
handleClick,
flagOperate,
getMileIcon,
getMileContent,
getLineColor,
handleFlagClick,
hexToRgb,
getFlagStyle
} from './index'
export const api = [
'state',
@ -28,7 +37,9 @@ export const api = [
'getMileContent',
'getMileFlagStyle',
'getLineColor',
'getStatus'
'getStatus',
'hexToRgb',
'getFlagStyle'
]
export const renderless = (
@ -47,7 +58,9 @@ export const renderless = (
handleFlagClick: handleFlagClick(emit),
handleClick: handleClick({ emit }),
getMileIcon: getMileIcon({ constants, props }),
flagOperate: flagOperate({ constants, refs, state })
flagOperate: flagOperate({ constants, refs, state }),
hexToRgb,
getFlagStyle: getFlagStyle(props)
}
return api

View File

@ -35,6 +35,10 @@ export interface IMilestoneIconStyle {
boxShadow: string
}
export interface IMilestoneFlagStyle {
left: string
}
export interface IMilestoneGetMileContentParams {
data: IMilestoneNode[]
index: number
@ -64,6 +68,8 @@ export interface IMilestoneApi {
handleClick: ({ index, node }: IMilestoneHandleClickParams) => void
getMileIcon: (node: IMilestoneNode) => IMilestoneIconStyle
flagOperate: ({ event, over, text }: IMilestoneFlagOperateParams) => void
hexToRgb: (hex: string) => { r: number; g: number; b: number }
getFlagStyle: ({ index, idx }) => IMilestoneFlagStyle
}
export type IMilestoneRenderlessParamUtils = ISharedRenderlessParamUtils<IMilestoneConstants>

View File

@ -0,0 +1,3 @@
export const tinyMilestoneAuroraTheme = {
'ti-milestone-icon-color': '#1890ff'
}

View File

@ -50,6 +50,13 @@
.iconfix {
font-size: var(--ti-common-font-size-4);
}
/* completed 节点 */
&.node-status-completed {
.@{milestone-prefix-cls}__line {
background-color: var(--ti-milestone-line-bg-color-completed);
}
}
}
& &__icon {
@ -60,29 +67,36 @@
position: relative;
font-size: var(--ti-milestone-font-size, 12px);
text-align: center;
left: ~'calc(50% - 10px)';
top: 4px;
left: var(--ti-milestone-icon-left);
top: var(--ti-milestone-icon-top);
border-radius: 50%;
color: var(--ti-milestone-text-color);
cursor: pointer;
z-index: 15;
border: var(--ti-milestone-icon-border-width) solid;
display: flex;
align-items: center;
justify-content: center;
.@{svg-prefix-cls} {
font-size: var(--ti-milestone-icon-size);
fill: var(--ti-milestone-icon-color);
vertical-align: baseline;
}
&.is-completed {
border: 2px solid;
.@{svg-prefix-cls} {
fill: #1890ff;
vertical-align: baseline;
}
border: var(--ti-milestone-icon-border-width-completed) solid;
}
}
& &__line {
height: 4px;
left: 50%;
top: -8px;
height: var(--ti-milestone-line-height);
width: var(--ti-milestone-line-width);
left: var(--ti-milestone-line-left);
top: var(--ti-milestone-line-top);
position: relative; // 里程碑线条不区分状态
background: var(--ti-milestone-line-bg-color);
background-color: var(--ti-milestone-line-bg-color);
}
& &__line-end {
@ -106,9 +120,10 @@
& &__description-status {
color: var(--ti-milestone-status-text-color);
font-size: var(--ti-milestone-font-size);
font-size: var(--ti-milestone-status-font-size);
float: left;
width: 100%;
margin-top: 4px;
}
& &__flag-tip {
@ -149,40 +164,49 @@
}
& &__flag-content {
width: 58px;
height: 34px;
padding: 0px;
line-height: 15px;
width: var(--ti-milestone-flag-width);
height: var(--ti-milestone-flag-height);
padding: var(--ti-milestone-flag-padding);
line-height: var(--ti-milestone-flag-line-height);
font-size: var(--ti-milestone-flag-content-font-size);
border-radius: var(--ti-milestone-flag-content-border-radius);
color: var(--ti-milestone-text-color);
background: #333;
background-color: var(--ti-milestone-flag-content-bg-color);
cursor: pointer;
vertical-align: middle;
display: table-cell;
p {
color: var(--ti-milestone-text-color);
width: 58px;
width: var(--ti-milestone-flag-width);
font-size: var(--ti-milestone-flag-font-size);
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
padding: 0 4px;
margin: 0;
box-sizing: border-box;
}
.@{milestone-prefix-cls}__flag-name {
font-weight: var(--ti-milestone-flag-name-font-weight);
}
.@{milestone-prefix-cls}__flag-desc {
color: var(--ti-milestone-flag-desc-text-color);
font-size: var(--ti-milestone-flag-desc-font-size);
line-height: var(--ti-milestone-flag-desc-line-height);
}
}
& &__flag-line {
height: 30px;
width: 1px;
margin-left: 50%;
background: #333;
margin-left: var(--ti-milestone-flag-line-margin-left);
background: var(--ti-milestone-flag-line-bg-color);
}
& &__dot {
display: block;
display: var(--ti-milestone-dot-display);
background: var(--ti-milestone-flag-line-color);
border: solid 1px;
border-radius: 50%;

View File

@ -0,0 +1,35 @@
export const tinyMilestoneSmbTheme = {
'ti-milestone-text-color': 'var(--ti-common-color-text-primary)',
'ti-milestone-icon-width': 'var(--ti-common-size-8x)',
'ti-milestone-icon-height': 'var(--ti-common-size-8x)',
'ti-milestone-icon-border-width': 'var(--ti-common-border-weight-normal)',
'ti-milestone-icon-border-width-completed': '1px',
'ti-milestone-icon-size': 'var(--ti-common-font-size-5)',
'ti-milestone-icon-color': 'var(--ti-common-color-icon)',
'ti-milestone-icon-left': 'calc(50% - 16px)',
'ti-milestone-icon-top': 'var(--ti-common-size-0)',
'ti-milestone-status-font-size': 'var(--ti-common-font-size-0)',
'ti-milestone-line-left': 'calc(50% + 24px)',
'ti-milestone-line-top': '-16px',
'ti-milestone-line-width': 'calc(100% - 48px)',
'ti-milestone-line-height': 'var(--ti-common-border-weight-normal)',
'ti-milestone-line-bg-color': 'var(--ti-common-color-bg-dark-disabled)',
'ti-milestone-line-bg-color-completed': 'var(--ti-common-color-bg-primary)',
'ti-milestone-flag-width': '88px',
'ti-milestone-flag-height': '46px',
'ti-milestone-flag-padding': 'var(--ti-common-size-base)',
'ti-milestone-flag-content-bg-color': 'var(--ti-common-color-bg-normal)',
'ti-milestone-flag-content-border-radius':
'var(--ti-common-border-radius-0) var(--ti-common-border-radius-4) var(--ti-common-border-radius-4) var(--ti-common-border-radius-0)',
'ti-milestone-flag-line-margin-left': 'var(--ti-common-size-0)',
'ti-milestone-flag-line-bg-color': 'var(--ti-common-color-bg-normal)',
'ti-milestone-flag-name-font-weight': 'var(--ti-common-font-weight-bold)',
'ti-milestone-flag-desc-text-color': 'var(--ti-common-color-text-secondary)',
'ti-milestone-flag-desc-font-size': 'var(--ti-common-font-size-0)',
'ti-milestone-flag-desc-line-height': 'var(--ti-common-line-height-base)',
'ti-milestone-flag-line-height': 'var(--ti-common-line-height-1)',
'ti-milestone-dot-display': 'none'
}

View File

@ -19,10 +19,44 @@
--ti-milestone-icon-width: var(--ti-common-size-5x, 20px);
// 节点高度
--ti-milestone-icon-height: var(--ti-common-size-5x, 20px);
// 节点默认边框色
--ti-milestone-icon-border-color: var(--ti-common-color-line-active);
// 节点默认边框粗细
--ti-milestone-icon-border-width: var(--ti-common-size-0);
// 完成节点边框粗细
--ti-milestone-icon-border-width-completed: var(--ti-common-border-weight-1);
// 节点图标大小
--ti-milestone-icon-size: var(--ti-common-font-size-base);
// 完成节点图标颜色
--ti-milestone-icon-color: #1890ff; // 保留原来样式,暂未适配默认主题 var(--ti-common-color-icon);
// 节点绝对定位左侧间距
--ti-milestone-icon-left: ~'calc(50% - 10px)';
// 节点绝对定位顶部间距
--ti-milestone-icon-top: var(--ti-common-size-base, 4px);
// 未完成线路背景色
--ti-milestone-line-bg-color: #dbdbdb;
// 完成节点线路背景色
--ti-milestone-line-bg-color-completed: #dbdbdb;
// 线高度
--ti-milestone-line-height: var(--ti-common-size-base, 4px);
// 线宽度
--ti-milestone-line-width: 100%;
// 线绝对定位左侧偏移
--ti-milestone-line-left: 50%;
// 线绝对定位顶部偏移
--ti-milestone-line-top: -8px;
// 节点下方日期文本色
--ti-milestone-status-text-color: var(--ti-common-color-placeholder, #adb0b8);
// 节点下方日期文本字号
--ti-milestone-status-font-size: var(--ti-common-font-size-1);
// 旗子宽度
--ti-milestone-flag-width: 50px;
// 旗子高度
--ti-milestone-flag-height: 34px;
// 旗子内间距
--ti-milestone-flag-padding: var(--ti-common-size-0, 0px) var(--ti-common-size-base, 4px);
// 提示行高(hide)
--ti-milestone-flag-tip-line-height: var(--ti-common-line-height-4, 20px);
// 提示背景色(hide)
@ -33,8 +67,27 @@
--ti-milestone-flag-content-border-radius: var(--ti-common-border-radius-1, 4px);
// 旗子默认字号(hide)
--ti-milestone-flag-content-font-size: var(--ti-common-font-size-1, 14px);
// 旗子背景色
--ti-milestone-flag-content-bg-color: #333;
// 旗子标题字重
--ti-milestone-flag-name-font-weight: var(--ti-common-font-weight-4);
// 旗子描述文本色
--ti-milestone-flag-desc-text-color: var(--ti-common-color-light, #fff);
// 旗子文本色
--ti-milestone-text-color: var(--ti-common-color-light, #fff);
// 旗子字号
--ti-milestone-flag-font-size: var(--ti-common-font-size-base, 12px);
// 旗子描述字号大小
--ti-milestone-flag-desc-font-size: var(--ti-common-font-size-base, 12px);
// 旗子行高
--ti-milestone-flag-line-height: 14px;
// 旗子描述行高
--ti-milestone-flag-desc-line-height: 14px;
// 旗子线绝对定位左侧间距
--ti-milestone-flag-line-margin-left: 50%;
// 旗子线背景色
--ti-milestone-flag-line-bg-color: #333;
// 旗子圆圈是否显示
--ti-milestone-dot-display: block;
}

View File

@ -16,7 +16,14 @@ export const $constants = {
DEFAULT_COLOR: '#1890FF',
DEFAULT_BACK_COLOR: '#FFFFFF',
BOX_SHADOW_PX: '0px 0px 0px 4px',
FLAG_CONTENT_CLS: '.content'
FLAG_CONTENT_CLS: '.content',
STATUS_MAP: {
COMPLETED: 'completed',
DOING: 'doing',
BACK: 'back',
END: 'end',
CANEL: 'canel'
}
}
export const milestoneProps = {

View File

@ -43,9 +43,7 @@
<div v-if="index < data.length - 1">
<div
v-for="(flag, idx) in getMileContent({ data, index })"
:style="{
left: `calc(${(100 / (data[flagBefore ? index : index + 1][flagField].length + 1)) * (idx + 1)}% - 29px)`
}"
:style="getFlagStyle({ index, idx })"
:key="idx"
:class="['tiny-milestone__flag', `flag-status-${flag[flagStatusField]}`]"
>
@ -63,8 +61,8 @@
@click="handleFlagClick({ idx, flag })"
>
<slot name="flag" :slot-scope="flag">
<p v-if="flag[flagNameField]">{{ flag[flagNameField] }}</p>
<p v-if="flag[flagContentField]" class="content">
<p v-if="flag[flagNameField]" class="tiny-milestone__flag-name">{{ flag[flagNameField] }}</p>
<p v-if="flag[flagContentField]" class="tiny-milestone__flag-desc content">
{{ flag[flagContentField] }}
</p>
</slot>